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

Should I include setState in useCallback's array of dependencies?

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

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

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

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

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

setState(newState);

During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.

Note

React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.

正如您正确暗示的那样,useCallback 的目的是 memoise:

useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

至于 useMemo 的用途:

You may rely on useMemo as a performance optimization, not as a semantic guarantee.

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

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

那么问题来了,你的'do something'下面是一个昂贵的计算吗?使用 useCallback 应该不会太麻烦,但它很可能是您不需要的 boilerplate code,并且几乎可以直接使用您的 setActive 功能。

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

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

在 useCallback 和其他挂钩中防止不必要依赖的另一种方法是使用 functional updates。结果是您可以拥有这些:

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 是 运行单击,而不是渲染。这显示在上面的第二个答案中,但没有解释。

另请参阅: