有没有办法在 for 中定义一个钩子?

时间:2021-02-10 12:31:09

标签: javascript reactjs react-hooks reducers

为了更多的优化/通用逻辑,我想制作一个使用多个 useCallback 的好 useSelectors

这里的 useSeletors 是在 useReducer 上制作选择器(就像在 redux 中一样)。 所以这是我的代码:

const useSelectors = (state, selectors) => useMemo(
    () => selectors.map(selector => 
        (...args) => (selector(state, ...args))
    ), 
    [state]
);

我想做的是:

const useSelectors = (state, selectors) => useMemo(
    () => selectors.map(selector => useCallback(
        (...args) => (selector(state, ...args))), 
        [state]
    ), 
    [state]
);

这实际上导致了错误。 我可能可以这样做:

const useSelectors = (state, selectors) => useMemo(
    () => selectors.map(selector => selector(state)), 
    [state]
);

但是我失去了在我的选择器函数中使用参数的可能性。
也许这不是问题,因为还有一些我还不明白的东西,关于 useCallback :
如果我使用 useCallback 而不提供参数但提供依赖,它几乎就像一个变量。
在我第一次调用它时,它被执行了吗?下一次(不更新依赖),直接得到函数的返回,不执行?

那么如果我在回调中放入变量参数(例如一个计数器)会发生什么?
即使依赖项没有改变,它是否可能会使用这个新参数重新执行函数?
那么 useCallback 结构是否因参数而变得无用?

最后一点,我想问的是:什么时候执行回调?
对于 useMemo,函数在声明时第一次执行? (或者我们第一次使用它的变量?=> 对于这种情况,差异并不重要。)
useCallback 是否只有在代码或声明中使用 () 调用时才第一次调用?
示例:

const myVar = useMemo(() => 5+5, [dependency]); // executed
const myFunc = useCallback(() => 5+5, [dependency]);

myVar; // 10
myFunc(); // executed => 10

myVar; // 10
myFunc(); // 10

因此,如果它像这样工作,最好在 useCallBack 中调用 useMemo,仅在调用时执行选择器,而不是在我的第三个解决方案中的挂载处执行。
这是我想在我的钩子中使用多个 useCallbacks 而不知道数字的主要原因。

[编辑]

useCallback 的第二个命题没有意义,因为:

const test = useCallback(() => {
        console.log('test is executed');
        return 'test';
    }, [state]);
    console.log(test());
    console.log(test());

日志:

执行测试
测试
测试执行
测试

并不是我所期望的:

执行测试
测试
测试

所以它不能比第一个做得更好

1 个答案:

答案 0 :(得分:0)

useCallback 返回一个函数。当该钩子的依赖项之一(例如,某个计数器)发生更改时,再次调用 useCallback 并返回新函数。这是因为传递给 useCallback 的函数在 useCallback 再次重新执行之前不知道计数器已更改。

useMemo 的工作原理相同,但它返回一个值。理论上,您可以使用 useCallback 实现 useMemo,返回函数而不是值。我的意思是 useCallback(fn, deps)useMemo(() => fn, deps) 相同。

您可以在 React docs 中阅读更多相关信息。

在您的代码中,您应该使用 useMemo 并且不要在 useCallback 内使用 useMemo,因为您会收到错误并且没有必要,因为它在将回调传递给优化的子组件依赖于引用相等来防止不必要的渲染。这不是你的情况。您的第一个代码示例是正确的。