首页 > 解决方案 > React hooks:可激活状态模式

问题描述

我正在尝试创建一个可以根据道具激活/禁用某些功能的组件。所有这些功能都需要一个必须管理的状态。

我试图考虑一种可能的模式,允许我们在连接的功能不活动的情况下不创建状态。我想到了两种可能的方法:

方式#1

function useFunctionality(initState, enable) {
    if (!enable) {
        return null;
    }

    const [funct, updateFunct] = useState(init);
    return funct;
}

function Component({ enableFunct }) {
    const funct = useFunctionality('test', enableFunct);
    return (...);
}

方式#2

function useFunctionality(initState, enable) {
    const [funct, updateFunct] = useState(init);
    return enable ? funct : null;
}

function Component({ enableFunct }) {
    const funct = useFunctionality('test', enableFunct);
    return (...);
}

在这两种方式中,钩子都会继续工作。问题是:你觉得哪种方式更正确?有更好的方法来做到这一点吗?

标签: reactjsdesign-patternsreact-hooks

解决方案


两种食谱都有问题。

方式 1 可能允许在组件渲染时有条件地调用钩子,这可能会导致错误并且不鼓励

不要在循环、条件或嵌套函数中调用 Hook。相反,请始终在 React 函数的顶层使用 Hooks。通过遵循此规则,您可以确保每次渲染组件时都以相同的顺序调用 Hook。这就是允许 React 在多个 useState 和 useEffect 调用之间正确保留 Hooks 状态的原因。

正如这个答案中所解释的,只要保证渲染之间的条件不会改变,就可以放弃这条规则。

保证这一点的一种方法是记住一个条件:

function useFunctionality(initState, enable) {
    const condition = useMemo(() => enable, []);

    if (!condition)
        return null;

    const [funct, updateFunct] = useState(initState);
    return funct;
}

方式 2 更可取,因为它更清洁,useState通话也不贵。

两种方式都有相同的问题,它们使用的状态永远不会改变。如果这是意图,那就是 ref 的用例。由于它永远不会改变,因此可以将条件设​​置为初始值:

function useFunctionality(initState, enable) {
    return useRef(enable ? initState: null).current;
}

推荐阅读