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

Posted

技术标签:

【中文标题】我应该在 useCallback 的依赖数组中包含 setState 吗?【英文标题】:Should I include setState in useCallback's array of dependencies? 【发布时间】:2019-09-08 07:48:11 【问题描述】:
    const [active, setActive] = useState(false);

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

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

【问题讨论】:

@AngelSalazar useState 中的更新程序方法没有被记忆或没有保留相同的引用? 我的错,根据文档“React 保证 setState 函数标识是稳定的,并且不会在重新渲染时改变。这就是为什么从 useEffect 或 useCallback 依赖列表中省略是安全的。” @AngelSalazar 感谢您的确认!我还在github.com/reactjs/reactjs.org/blob/master/content/docs/… 中找到了那部分,所以只需传递一个空数组就可以了。您可以将其作为此问题的答案,或者我将发布我自己问题的答案。 【参考方案1】:

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

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

setState(newState);

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

注意

React 保证 setState 函数的身份是稳定的,不会 更改重新渲染。这就是为什么从 useEffect 中省略是安全的 或者 useCallback 依赖列表。

【讨论】:

【参考方案2】:

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

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

至于useMemo 的用途:

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

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

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

那么问题来了,您的“做某事”是否低于昂贵的计算?使用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 中的工作方式与 nuance 有关,您应该使用箭头功能,因此您的 setActive 在单击时运行,而不是渲染。这在上面的第二个答案中显示,但没有解释。

另见:What is useState() in React?

【讨论】:

以上是关于我应该在 useCallback 的依赖数组中包含 setState 吗?的主要内容,如果未能解决你的问题,请参考以下文章

React Hook useCallback 缺少依赖项:'Id'。包括它或删除依赖数组[重复]

如何在清单文件中包含 Maven 依赖项

使用 webpack 在 Vue PWA 中包含大型 js 依赖项

如何在 .NET Core 应用程序 docker 映像中包含依赖项?

Maven - 在 jar 中包含依赖库而不解包依赖项?

使用 Maven Surefire 运行依赖项 jar 中包含的 JUnit 测试