ReactJS Hooks 总结

Hooks 定义

Hook 就是钩子的意思。为了在函数组件中使用类组件的生命周期、状态管理等一些类组件特性,所以引入了 hooks.
需要注意的是:在类组件中是不能够使用hooks的。

Hooks 使用规则

  • Hooks只能在顶层调用,不能在循环、条件判断或者嵌套函数中调用hook函数。
// 错误写法 
if(a===b){
  useEffect(()=>{
    //...
  },[...])
}
  • 只能在函数组件中使用hooks,不能在类组件中使用
  • 可以使用 eslint-plugin-react-hooks插件规范hooks代码

Hooks 优缺点

优点

  • 代码容易复用(可以自定义useState)
  • 代码可读性强。代码好看些,每个功能都在函数中代码量少
  • 组件层级变少
  • 不需要考虑this 的指向问题

缺点

  • 响应式的 useEflect , useCalbask 的作用、第二个参数(依赖项数组)的改变时机不容易把握。
  • 状态不同步,不在同一个 ui 线程,同一个变量,会显示不同的值。可以使用 useRef 改善。
  • 状态管理容易出错
  • 需要了解所有 hooks 函数

函数列表

useState

  • 用来声明状态变量,类似类组件class 中的this.setState({a:'abc'})。而且函数的渲染每次都是独立的(异步),这也就是 Capture Value 特性
  • 示例
// 定义
const [nameState, setName] = useState("");// useState 的参数为设定的默认值
const [age, setAge] = useState(1);
// 使用
setName("ABC");
setAge(25);
  • 点击按钮改变nameState值,当回车 Enter(或者不在同一个线程中,初始时注册的方法等)提交时,获取 nameState 值,这时发现nameState还是默认的初始值。例如:点击按钮提交和按回车键提交,点击按钮提交是可以获取到值的,按回车键提交获取值失败。
  • 解决方法:
    • 方法一
const [nameState,setName]=useState();
const lastNameState = useRef(nameState);
// 改变 lastNameState 值 
useEffect(()=>{
  lastNameState.current= nameState;
}[nameState]);
// 点击按钮时,调用setName 
const onClick=(e)=>{
  setName(e.currentTarget.value)
}
  • 方法二
useEffect(()=>{
  setName(name)
},[name]);
//点击按钮时,发送一个action,改变reducer 的state值 
const onClick=(e)=>{
  putName(e.currentTarget.value)
}
//...
// Action
export function putName(name){
  return{
    type:"CHANGE_NAME", 
    payload: { name }
  }
}

useEffect

  • 网上都叫其副作用,我也不明白为啥都叫副作用 ♂️,我更倾向于叫响应。
  • 其替代类组件声明周期函数: componentDidMount、componentWillUnmount、componentDidUpdate。
  • 示例
// componentDidMount || componentWillUnmount
useEffect(()=>{
// componentDidMount
// ...

// componentWillUnmount 
return ()=>{
  //...
},[]);

// componentDidMount || componentDidUpdate 
useEffect(()=>
  setName(name)
),[name]);// 从父组件传递过来的name,当name 发生变化时,更新nameState

useContext

  • 用来处理多层级传递数据,减少组件的嵌套。
  • 示例
function Children(){
  const color = useContext(colorContext);
  return <div>{color}</div>
}

function Parent(){
  return <Children/>
}

const colorContext = createContext("gray");// React.createContext();
function App(){
  return (
    <colorContext.Provider value={"red"}>
      <Parent/>
    </colorContext.Provider>
  )
}

useReducer

  • 可以看成是react-redux 使用方式的缩小版。不能使用redux 提供的中间件。
  • 可以看成是useState 的替代方案
  • useReducer(reducer, initialState, init())。reducer函数,接收state和action; initialState是需要设定的state的初始值;init()是通过方法来初始化state,这样可以情性的创建初始state。
  • 示例
const initialState =0;
const init = (v) =>{
    return v;
}

const testReducer =(state, action)=>{
    switch(action){
        case "add":
            return state+1; 
        case"sub":
            return state-1; 
        case "reset":
            return init(action.payload); 
        default:
            return state;
    
    }
}

const[count, calculationDispatch]= useReducer(testReducer, initialState);
// const[count, calculationDispatch] = useReducer(testReducer, initialState, init); 
return(
    <div>
        <div>{count}</div>
        <button onClick={()=>calculationDispatch("add")}>ADD</button>
        <button oClick={()=>calculationDispatch("sub")}>SUB</button>
        <button oClick={()=>calculationDispatch({type: "reset",payload:initialState})}>RESET</button>
    </div>
)

useCallback

  • 获得一个记忆函数,避免在某些情况下子组件的重复渲染。一般用来做性能优化。
  • useCallback 返回的是一个函数
  • useCallback(function,[...])。两个参数,第一个参数是需要记忆的画数,第二个参数是当数组内的值发生变化了,才执行function。
  • 示例
const [text, setText] = useState(""); 
const submit = useCallback(()=>{
    console.log(text)
}, [text]);

return(
    <div>
        <input value={text} onChange={(e)=>setText(e.target.value)}/>
        <button onClick={submit}>Submit</button>
    </div>
)

useMemo

  • 获得一个记忆组件,适用于返回确定的值
  • 类似useCallback,但是useCallback返回的是需要执行的函数,而useMemo 返回的是执行函数返回的值
  • 示例
const [text, setText] = useState(""); 
const textMemo = useMemo(()=>{
    return text+"time"
}, [text]);
return(
    <div>
        <input value= {text} onChange={(e)=>setText(e.target.value)}/>
        <input value={textMemo}/>
    </div>
)

useRef

  • 生成对DOM对象的引用。
  • 类似于 createRef,但是它是真正的引用,而不是把值copy 过去。
  • 与useState很像,可以把它看成是render的全局变量,而useState是每个render中局部变量; useRef.current 不会触发Ul的重新渲染,而useState会触发Ul的重新渲染。
  • 示例
const [name, setName] = useState("");
const nameRef = useRef(name);
const submit =() =>{
    setName(nameRef.current);
}
return(
    <div>
        <p>{name}</p>
        <div>
            <input ref ={nameRef}/> 
            <button onClick={submit}>Submit</button>
        </div>
    </div>
)

useImperativeHandle

  • 穿透Ref,用于父组件获取子组件的引用
  • 示例
function ChildInputComponent(props, ref){
    const inputRef = useRef(null);
    useImperativeHandle(re, ()=>inputRef.current); 
    return(
        <div>
            <input name="input1" ref={inputRef} placeholder="yes"/>
            <input name="input1" placeholder="nonono"/>
        </div>
    )
}

const ChildInput = forwardRef(ChildInputComponent);
function App(){
    const inputRef = useRef(null);
    useEffect(()=>{
        inputRef.current.focus()
    },[]); 
    
    return(
        <div>
            <ChildInput ref={inputRef}/>
        </div>
    )
}

useLayoutEffect

  • 同步执行,在页面完全渲染完成后,操作 dom, 会优于 useEffect 异步触发函数。

其他

memo

  • 用来包裹函数式组件的
  • 当用React.memo包裹组件时,当组件内的useState或useContext 发生变化时,才会重新渲染面面。
  • memo(Component, propsAreEqual(preProps, nextProps));第一个参数为函数组件,第二个参数为比较规则,若不传递则默认为props 浅比较。

forwardRef

  • 主要用来进行DOM 穿透的
  • 示例
const AButton = React.forwardRef((props, ref)=>(
    <button ref={ref} {...props}>
    {props.children}</button>
))

class BButton extends React.Component{
    this.testRef = React.createRef();
    onClick =()=>{
        // 打印出 AButton 中button 的信息 
        console.log(this.testRef.current)
    };

    render(){
        return(
            <div>
                <AButton ref = {this.testRef} onClick={onClick}>AButtan</AButton>
            </div>
        )
    }

}

总结

这里只罗列了hooks 函数的基本用法,想要更深层次的掌握react 的知识,需要不断的去实践。只有在不断的使用各种技巧、各种功能,才会越发的了解掌握更深入的内容。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容

  • 1. hooks总览 什么是react 的 hook 以及 react hooks 的由来 官网解释:Hook 是...
    雨溪滩阅读 1,809评论 0 8
  • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他...
    mora__阅读 590评论 0 0
  • 什么是hooks? hooks 是 react 在16.8版本开始引入的一个新功能,它扩展了函数组件的功能,使得函...
    JoeRay61阅读 562评论 0 0
  • 前言 文章虽然比较长,但是可以说是全网最全最有用的总结了,学会的记得分享、点赞、收藏、谢谢支持 React 在 v...
    流动码文阅读 1,058评论 0 2
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,536评论 28 53