React18 (六) hook钩子函数

React中的钩子函数的功能非常的强大,而它的使用又十分简单。关于钩子函数的使用,我们只需记住两点:

1. 钩子只能在React组件和自定义钩子中使用
2. 钩子不能在嵌套函数或其他语句(ifswitch、white、for等)中使用

React中自带的钩子函数

useState
useEffect
useContext
useReducer
useCallback
useRef
useMemo
useImperativeHandle
useLayoutEffect
useDebugValue(18.0新增)
useDeferredValue(18.0新增)
useTransition(18.0新增)
useId(18.0新增)
useSyncExternalStore(18.0新增)
useInsertionEffect(18.0新增)

UseMemo

useMemo和useCallback十分相似,useCallback用来缓存函数对象,useMemo用来缓存函数的执行结果。在组件中,会有一些函数具有十分的复杂的逻辑,执行速度比较慢。闭了避免这些执行速度慢的函数返回执行,可以通过useMemo来缓存它们的执行结果,像是这样:

const result = useMemo(()=>{
    return 复杂逻辑函数();
},[依赖项])

useMemo中的函数会在依赖项发生变化时执行,注意!是执行,这点和useCallback不同,useCallback是创建。执行后返回执行结果,如果依赖项不发生变化,则一直会返回上次的结果,不会再执行函数。这样一来就避免复杂逻辑的重复执行。

UseImperativeHandle

在React中可以通过forwardRef来指定要暴露给外部组件的ref:

const TestButton = forwardRef((props, ref) => {
    return <button ref={ref}>Test</button>
});

上例中,TestButton组件将button的ref作为组件的ref向外部暴露,其他组件在使用TestButton时,就可以通过ref属性访问:

<TestButton ref={btnRef}/>

通过useImperativeHandle可以手动的指定ref要暴露的对象,比如可以修改TestButton组件如下:

const TestButton = forwardRef((props, ref) => {

    useImperativeHandle(ref,()=> {
        return {
            name:'test-button'
        };
    });

    return <button>test</button>
});

useImperativeHandle的第二个参数是一个函数,函数的返回值会自动赋值给ref(current属性)。上例中,我们将返回值为{name:'test-button'}。实际开发中,我们可以将一些操作方法定义到对象中,这样可以有效的减少组件对DOM对象的直接操作。

const TestButton = forwardRef((props, ref) => {

    const btnRef = useRef();

    useImperativeHandle(ref,()=> {
        return {
            setDisabled(){
                btnRef.current.disabled = true;
            }
        };
    });

    return <button ref={btnRef}>Disable</button>
});

const App = () => {
    
    const btnRef = useRef();

    const clickHandler = () => {
        btnRef.current.setDisabled();
    };

    return <div>
        <TestButton ref={btnRef}/>
        <button onClick={clickHandler}>ok</button>
    </div>;
};

UseLayoutEffect

useLayoutEffect的方法签名和useEffect一样,功能也类似。不同点在于,useLayoutEffect的执行时机要早于useEffect,它会在DOM改变后调用。在老版本的React中它和useEffect的区别比较好演示,React18中,useEffect的运行方式有所变化,所以二者区别不好演示。useLayoutEffect使用场景不多,实际开发中,在effect中需要修改元素样式,且使用useEffect会出现闪烁现象时可以使用useLayoutEffect进行替换。

UseDebugValue

用来给自定义钩子设置标签,标签会在React开发工具中显示,用来调试自定义钩子,不常用。

UseDeferredValue

useDeferredValue用来设置一个延迟的state,比如我们创建一个state,并使用useDeferredValue获取延迟值:

const [queryMember, setQueryMember] = useState('');
const deferredQueryMember = useDeferredValue(queryMember);

上边的代码中queryMember就是一个常规的state,deferredQueryMember就是queryMember的延迟值。设置延迟值后每次调用setState后都会触发两次组件的重新渲染。第一次时,deferredQueryMember的值是queryMember修改前的值,第二次才是修改后的值。换句话,延迟值相较于state来说总会慢一步更新。延迟值可以用在这样一个场景,一个state需要在多个组件中使用。一个组件的渲染比较快,而另一个组件的渲染比较慢。这样我们可以为该state创建一个延迟值,渲染快的组件使用正常的state优先显示。渲染慢的组件使用延迟值,慢一步渲染。当然必须结合React.memo或useMemo才能真正的发挥出它的作用。

UseTransition

当我们在组件中修改state时,会遇到复杂一些的state,当修改这些state时,甚至会阻塞到整个应用的运行,为了降低这种state的影响,React为我们提供了useTransition,通过useTransition可以降低setState的优先级。useTransition会返回一个数组,数组中有两个元素,第一个元素是isPending,它是一个变量用来记录transition是否在执行中。第二个元素是startTransition,它是一个函数,可以将setState在其回调函数中调用,这样setState方法会被标记为transition并不会立即执行,而是在其他优先级更高的方法执行完毕,才会执行。除了useTransition外,React还直接为为我们提供了一个startTransition函数,在不需要使用isPending时,可以直接使用startTransition也可以达到相同的效果。

UseId

生成唯一id,使用于需要唯一id的场景,但不适用于列表的key。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章