在 React 16 以前,我们都使用 setState 来完成数据的更新,而 setState 是支持回调的。但是在 React 17 里,useState 却不支持回调,这对使用者来说有时有些不便,而我正好碰上了需要使用回调的场景。

前言

一般而言, useState 可以直接搭配 useEffect 监听数据的变更来假性的实现一个回调效果。但是如果需要支持回调的数据比较多,那么我们需要给这些数据都手动搭配 useEffect

这样多的辅助代码对于业务代码来说是一种侵入式的,一定程度影响了代码阅读体验。对于这些类似的代码,完全可以封装成一个工具性的方法进行使用,弱化“回调”的内部实现。

令我感到困惑的是,我在 ahooks 库里面见不到 useCallbackState 的身影……

所以我决定自己封装了一个 useCallbackState

封装

“回调”的实现原理很清晰,那就是使用 useEffect 监听数据的变更来模拟回调。另外还有一点,需要使用一个变量来存储在 useCallbackState 中传入的待执行的回调,而这样的任务交给 useRef 是再适合不过了。

具体代码如下:

import {useRef, useState, useEffect, SetStateAction} from 'react';

interface Callback<S> {
    (state: S): void;
}

interface ReturnCallback<S> {
    (state: SetStateAction<S>, callback?: Callback<S>): void;
}

function useCallbackState<T>(initState: T): [T, ReturnCallback<T>] {
    const cbRef = useRef<Callback<T>>();
    const [state, setState] = useState(initState);

    useEffect(() => {
        cbRef.current?.(state);
    }, [state]);

    return [
        state,
        function setAndCallback(state: SetStateAction<T>, callback?: Callback<T>) {
            cbRef.current = callback;
            setState(state);
        }
    ];
}

export {useCallbackState};

这样一个叫 useCallbackState 的 hooks 就诞生了。