我应该在 useCallback 的依赖项数组中包含 setState 吗?

IT技术 reactjs react-hooks
2021-05-18 13:14:11
    const [active, setActive] = useState(false);

    const onActiveChanged = useCallback(
      isActive => () => {
        // do something
        setActive(isActive);
      },
      [setActive], // or just [] is okay?
    );

useStateuseCallback(或useMemo)一起使用时,我应该包含setState在依赖项数组中吗?

2个回答

对此的建议也在React Docs - Hooks API Reference 上

setState 函数用于更新状态。它接受一个新的状态值并将组件的重新渲染排入队列。

setState(newState);

在随后的重新渲染期间, useState 返回的第一个值将始终是应用更新后的最新状态。

笔记

React 保证 setState 函数标识是稳定的,并且不会在重新渲染时发生变化。这就是为什么从 useEffect 或 useCallback 依赖项列表中省略是安全的。

useCallback正如您正确暗示那样,目的记住

useCallback(fn, deps) 等价于 useMemo(() => fn, deps)。

至于用于什么useMemo

您可以依赖 useMemo 作为性能优化,而不是语义保证。

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

但作为一项规则,useState在渲染之间是稳定的(即预先记忆),所以你不需要再次记忆它

那么问题来了,您的“做某事”是否低于昂贵的计算?使用 应该不会很麻烦useCallback,但它很可能是您不需要的样板代码,并且几乎可以直接使用您的setActive函数。

const [active, setActive] = useState(false);

const onActiveChanged = useCallback(
  isActive => () => {
    // do something
    setActive(isActive);
  },
  [setActive], // or just [] is okay?
);

在 useCallback 和其他钩子中防止不必要的依赖的另一种方法是使用功能更新结果是你可以拥有这些:

const [active, setActive] = useState(false);
const [expensiveCalc, setExpensiveCalc] = useState(false);

const onExpensiveCalc = useCallback(
  expensiveInput => () => {
    const newState = doExpensiveCalc(expensiveInput);
    expensiveCalc(newState);
  },
  [setActive], // here for completeness
);

return (<>
  // expensive calculation
  <button onClick={onExpensiveCalc}>Do lengthy calculation</button>
  // cheap calculation, using functional updates
  <button onClick={() => setActive(prevBoolean => !prevBoolean)}>Cheap Set Active</button>
</>)


请注意,在 onClick 中设置状态的工作方式有一些细微差别,您应该使用箭头函数,因此您setActive在单击时运行,而不是渲染。这显示在上面的第二个答案中,但没有解释。

另请参阅:React 中的 useState() 是什么?