美文网首页
React Hooks 学习总结

React Hooks 学习总结

作者: alex夏夜 | 来源:发表于2020-05-24 20:54 被阅读0次

    前言

    最近的换写React项目了,好久没有写React,还动不动就想class🤣,现在跟上时代,重新学习React Hook.Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

    为什么有Hook?

    1、在组件之间复用状态逻辑比较难,需要用到高阶组件或者render props,Hook可以无需修改组件结构的情况下,复用状态逻辑。
    2、Hook可以将组件中相互关联的部分拆分成更小的函数,方便理解;
    3、不再使用class和this,更方便上手和理解;

    使用Hook的注意事项

    1、只能在最外层函数中调用Hook。(不要在循环、条件判断、子函数中调用)
    React在创建hook时,以链表的解构存储,前一个hook中next指针指向下一个hook。在组件更新时会进行hook的一一对应的比对,所以要保证每次hook数量一致,位置相同。循环、条件判断中使用hook,会导致数量和位置的变化,产生错误。
    2、只在react的函数组件中调用。

    常用的HooK

    1.useState

    • 作用:在组件内部添加一个state,React会在重复渲染时保留这个state。
    • 参数: 1个,state的初始值initialState;
    const [state,setState] =useState(initialState)
    
    • 返回值 :2个
      1)state 当前状态,在初始渲染时,state就是initialState
      2)setState更新当前state的函数,他接受一个新的state,并且将该组件的一次渲染加入队列,他有点类似类组件中this.setState,但并不会将新旧state合并
    //在函数组件中
    const [state,setState] =useState({name:"lily",age:18})
    return(
    <button onclick={setState({age:20})}>改变年龄<button>
    //这里使用useState不会将新旧state,现在state为{age:20},name属性就没有了
    //所以需要注意 onclick={setState({...state,age:20})}
    )
    
    • 特点
      1) 每次渲染都是独立的闭包,拥有当前自己的props\state\函数
      2)函数式更新
    //如果新的状态需要依赖旧的状态,可以使用函数式更新
    setState(state =>({...state,age:state.age +1}))
    //将旧状态传入,返回新的状态
    

    3)懒加载初始化state

    //如果state中的值需要复杂计算
    const [state,setState] =useState(()=>  ({name:"lily",age:12}))
    
    • 性能优化(减少渲染次数)
      1)Object.is
      在调用state的更新函数时,React会先进行Object.is的比较算法
      如果state不相同,进行子组件渲染和effect,否则不进行刷新渲染

    2)useMemo(缓存值)
    某些情况下组件中的值需要依赖state进行计算后得到,由于每次组件更新都会去重新计算,为了减少性能消耗,可以使用useMemo缓存值,仅仅当依赖改变时,才重新计算。

    • 参数:计算函数,依赖数组
      则函数仅会在某个依赖项改变时才重新计算memoized 值。
     const [count, setCount] = useState(0);
    //expensive 需要依赖count计算得到
     const expensive = useMemo(() => {
     let sum = 0;
     for (let i = 0; i < count; i++) {
     sum += i;
     }
     return sum;
     //只有count变化,这⾥才重新执⾏
     }, [count]);
    

    3)useCallback (缓存回调函数)
    由于每次组件更新都会内部函数都会重新创建一次,为了节省性能,可以使用useCallback,使内联回调函数仅仅在传入依赖项改变时进行更新。

    • 参数:内联回调函数,依赖数组
      则函数仅会在某个依赖项改变时才进行更新。
     const [count, setCount] = useState(0);
     const addClick = useCallback(() => {
    setCount(count+1)
     }, [count]);
    

    4)memo (缓存组件)
    父组件更新子组件也会重新创建,为节省性能,可用memo将子组件缓存,仅仅当props改变时,组件才进行更新

    const Child = (props)=>{
    return <div>{props.age}</div>
    }
    //这里只会在props改变的时候重新渲染
    Child =memo(Child)
    const Father=()=>{
    const [name,setName]=useState("lily")
    const [age,setAge]=useState(18)
    return(
    <>
    <button onclick={setAge(age+1)}>改变年龄<button>
    <input onChange={e=>(setName(e.target.value))}>改变姓名<button>
    <Child age={age}/> 
    </>
    )
    }
    

    5)useRef (缓存ref)
    同理,用useRef可对React.creactRef对象进缓存

    2. useReducer

    • 作用:编写自定义hook或者在某些改变state逻辑复杂的情况下替代useState,用法类似redux,useState是useReducer的语法糖。
    • 参数: 3个,reducer方法 、initialState初始值,init;
    const [state,dispatch] =useReducer(reducer ,initialState)
    
    • 返回值 :2个
      1)state当前状态,在初始渲染时,state就是initialState
      2)dispatch派发方法,接受参数action,改变当前state,并且将该组件的一次渲染加人队列。

    • 自定义hook

    //实现一个useState
    const useState=(initalState)=>{
        const reducer = useCallback(_state,action)=>{
            return action.paylaod
        }
        const [state,dispatch] = useReducer(reducer, initalState)
        const setState = (state)=>{
            dispatch({paylaod:state})
        }
        return [state,setState]
    }
    

    3.useContext

    • 作用:提供更方便的方法从React上下文中拿到consumer的值
      参数: 1个,context(React.createContext);
    const  value=useContext(context)
    
    • 返回值 :1个 consumer的值

    4.useEffect

    • 作用:在React渲染阶段,改变DOM、添加订阅、设置定时器等操作会破坏UI一致性,含有副作用的操作将不被允许,使用useEffect完成副作用的操作,传入函数会在组件渲染后执行.
    • 参数: 2个,didUpdate包含副作用的回调函数,在组件渲染后执行,[state]依赖项,传入依赖项,仅在依赖项改变后的执行
    useEffect(didUpdate,[state])
    
    • 返回值 :1个 清除副作用函数,在组件销毁前执行,相当于componentWillUnmount,可进行定时器,事件监听的移除操作
    • 特点
      由于useEffect的副作用函数在组件渲染后执行,他和class组件中的 生命周期componentDidMount/componentDidUpdate和componentWillUnmount有相同的用途

    5.useRef、useImperativeHandle

    • useRef作用:对ref对象进缓存,ref 对象在组件的整个生命周期内保持不变。
    • 参数: 1个,initialValue,ref.curren初始化的值
    function  FocusButton() {
        const inputEl = useRef(null); 
        const onButtonClick = () => {
            // `current` 指向已挂载到 DOM 上的文本输入元素
            inputEl.current.focus();
        };
        return (
            <>
                <input ref={inputEl} type="text" />
                <button onClick={onButtonClick}>Focus the input</button>
            </>
        );
    }
    
    
    • useImperativeHandle作用:有些情况下我们需要父组件把ref传递给子组件,仅仅使用forwardRef将子组件的ref属性都暴露给父组件是危险的,也违反了封装原则,useImperativeHandle允许在子组件中把自定义实例附加到父组件传过来的ref上,减少暴露给父组件的属性
    • 参数: 3个,ref, createHandle处理函数,其返回值会替换父组件传来的ref.current, [state]依赖项
    useImperativeHandle(ref, createHandle, [state])
    
    • 例子
    let Child =  (props, ref) =>{
        const inputRef = useRef();
        useImperativeHandle(ref, () => ({
            focus: () => {
                inputRef.current.focus()
            }
        }));
        return <input ref={inputRef} />;
    }
    Child = forwardRef(Child );
    
    const Father=() => {
        const ref = useRef(null);
        return (
            <>
                <Child ref={ref}/>
                 <button onClick={()=>{ ref.current.focus()}}>聚焦</button >
            </>
        )
    }
    

    6.useLayoutEffect

    • 作用 :与useEffect相同,都是用来执行副作用。
    • 特点 :useEffect是在渲染之后调用effect,也就是下一桢执行,是异步的;
      而useLayoutEffect在当前帧Render tree计算布局(Layout)信息后,渲染前,同步调用effect。官方文档建议使用标准useEffec。

    7.自定义Hook

    • 定义:函数以use开头并且在函数内部调用其他hooks,并且返回一个数组,可以实现逻辑复用。
    • 例子 :
    //实现一个thunk
    const useThunk =(reducer,initalState)=>{
    const [state,dispatch] =useReducer(reducer,initalState)
    const thunkDispatch = (action)=>{
    if( action instanceof Function){ //如果action是函数,传入新的dispatch执行action
       return action (thunkDispatch,()=>state)
    }else{
    dispatch(action )
    }
    return [state,thunkDispatch]
    }
    
    
    

    结尾

    现在就只了解到这么多。还有什么没写到的日后更新。

    相关文章

      网友评论

          本文标题:React Hooks 学习总结

          本文链接:https://www.haomeiwen.com/subject/nfdrahtx.html