React Hooks补充

76 阅读3分钟

useReducer

  1. 规定了数据是单向流动的
  2. 数据存储在数据仓库中(可以认为数据就是当前组件内的state)
  3. action是改变数据的唯一原因(本质上就是一个对象,action有两个属性)
  • type:string 规定动作的类型
  • payload:any 动作发生后的附加信息
  1. 具体改变数据的是一个函数,该函数叫做reduce(纯函数,不能有副作用),该函数必须返回结果,用于表示数据仓库变化之后的数据(Flux要求,对象是不可变的,如果返回对象,必须创建新的对象),该函数不可直接调用,必须借助dispatch触发,该函数接收两个参数
  • state:数据仓库中的数据
  • action: 描述了如何改变数据
使用
import { useReducer } from 'react
/***
* reducer reducer函数
* initState 初始状态
* fn 接收一个参数,是initState,返回一个状态,此状态会覆盖initState
/
const [state, dispath] = useReducerr(reducer, initState, fn);
useReducer实现过程
export default function useReducer(reducer, initState,fn) {
    const [state, setState] = useState(fn ? fn(initState) : initState);
    
    function dispath(action) {
        const newState = reducer(state, action);
        conole.log(`变量值${state}-->${newState}`);
        setState(newState);
    }
    
    return [state, dispath];
}

useContext

用于获取上下文数据,减少组件嵌套

import React from 'react'

const ctx = React.createContext();
// 方法一
function Test() {
    return <ctx.Consumer>
        {value => <div>上下文的值:{value}</div>}    
    </ctx.Consumer>
}
// 方法二
function Test() {
    const value = useContext(ctx);
    return <div>上下文的值:{value}</div>
}

export default function App() {
    return (
        <ctx.Provider value="test">
            <Test />
        </ctx.Provider>
    )
}

useCallback

用于得到一个固定引用值的函数,通常用来做性能优化

该函数有两个参数:

  • 函数,useCallback会固定该函数的引用,只要依赖项没有发生变化,则始终返回之前函数的地址
  • 数组,记录依赖项
// 纯组件会进行浅比较,如果值一致不应该发生渲染
class Son extends React.PureComponent {
    render() {
        return <div>
            <div>{this.props.text}</div>
            <button onClick={this.props.onClick}>改变文本</button>
        </div>
    }
}

function Parent() {
    const [n, setN] = useState(0);
    const [val, setVal] = useState('');
    // 方法一
    const handleClick = () => {
        setN(Math.random());
    };
    // 方法二
    const handleClick = useCallback(() => {
        setN(Math.random());
    }, []);
    return (
        <div>
            // 函数地址每次渲染都发生了变化,导致子组件重新渲染,若子组件是经优化过的组件,则可能导致优化失效
            <Son text={n} onClick={handleClick} />
            <input type="number"
                value={n}
                onChange=(e => setN(e.target.value))
            />
        </div>
    )
}

function App() {
    return (
        <div>
            <Parent />
        </div>
    )
} 

每次执行setN,状态变化时,方法一都会返回一个新的函数引用;方法二只要依赖项不发生变化,都会返回之前的函数引用。

useMemo

用于保持一些比较稳定的数据,一般用于高开销的性能场景,做性能优化

 // 和useCallbakc使用区别,useCallback返回函数本身,useMemo返回新函数
 const handleClick = useMemo(() => {
     return () => {
         setN(Math.random());
     }
 }, []);
 
 // 比如渲染10000个数,只要依赖项不发生变化,其他状态的改变不应该影响这个组件的渲染
 const list = useMemo(() => {
     const list = [];
     for(let i = 0; i < 10000; i++) {
         list.push(<Item key={i} value={i} />)
     }
     return list;
 }, []);

useLayoutEffect

时间点: 操作DOM--->(componentDidMount、componentDidUpdate、useLayoutEffect) ---> 用户看到新的效果 ---> useEffect

  • useEffect: 浏览器渲染完成后,用户看到新的渲染结果之后(会先渲染完毕再操作,不会一直白屏卡住)
  • useLayoutEffect: 完成了DOM改动,还没呈现给用户(相当于componentDidMount、componentDidUpdate)

尽量使用useEffect,因为他不会阻塞渲染,如果出现了问题,再考虑使用useLayoutEffect