是否需要 useMemo 通过 reactjs 中的上下文 API 来管理状态?

Tim*_*Tim 14 state reactjs react-hooks

我试图理解这篇(主要是非常有用的)文章,它描述了如何使用 react 的上下文 API 来管理应用程序级状态。对于一个简单的应用程序(在这种情况下是一个基本的计数器应用程序),它使用以下解决方案:

const CountContext = React.createContext()

function CountProvider(props) {
  const [count, setCount] = React.useState(0)
  const value = React.useMemo(() => [count, setCount], [count])
  return <CountContext.Provider value={value} {...props} />
}
Run Code Online (Sandbox Code Playgroud)

提供上下文,然后提供以下钩子,它可以在组件树下某处的组件中使用:

function useCount() {
  const context = React.useContext(CountContext)
  if (!context) {
    throw new Error(`useCount must be used within a CountProvider`)
  }
  return context
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

我正在努力理解为什么useMemo这里需要钩子。这里没有涉及特别繁重的计算,所以我不确定我们为什么要记住这些值。如果上下文提供程序如下所示,这是否也能正常工作:

function CountProvider(props) {
  const [count, setCount] = React.useState(0)
  return <CountContext.Provider value={value} {...props} />
}
Run Code Online (Sandbox Code Playgroud)

我觉得可能有什么我错过了!!

Shu*_*tri 17

关于为什么应该使用 useMemo 来记忆返回给 Context Provider 的值,有一个非常简单的理论。当您将值作为对象或数组传递给上下文提供程序时

return <CountContext.Provider value={{state, setCount}} {...props} />
Run Code Online (Sandbox Code Playgroud)

或者

return <CountContext.Provider value={[state, setCount]} {...props} />
Run Code Online (Sandbox Code Playgroud)

本质上发生的是,每次 CountProvider 组件重新呈现对对象或数组的新引用时,都会作为值传递给CountContext.Provider,因此即使实际值可能没有改变,上下文使用者也会重新呈现,因为引用检查失败价值

现在,您可能需要也可能不需要 useMemo,具体取决于您的ContextProvider. 例如,在您的情况下,CountContext它只是使用一种状态,即计数并将其传递给子项,如果它CountContext是顶级元素之一,除了计数更改之外,它不会被任何重新渲染,那么在这种情况下,您是否使用useMemo与否没有区别,因为返回值的引用useMemo也在计数更改时更新

但是,如果您有某些CountProvider可能导致CountProvider重新渲染的父级,useMemo记住上下文值会派上用场,以避免重新渲染所有上下文使用者

  • 很高兴能提供帮助:-) (2认同)

Joe*_*oyd 14

调用 setCount 将始终重新渲染组件

我相信调用 setCount 总是会重新渲染,即使将相同的值传递给函数也是如此。

但线

const value = React.useMemo(() => [count, setCount], [count])
Run Code Online (Sandbox Code Playgroud)

将停止调用 setCount 除非计数有不同的值。从而减少重新渲染并提高性能。

您可以通过将日志放入其中并查看组件在使用和不使用 useMemo 的情况下如何呈现来测试该理论。

  • 当然,另一个答案给出了更多的深度。我很高兴能帮助反应爱好者! (3认同)
  • `const value = useMemo(() =&gt; ({ count, setCount}), [count]);` 第一个参数应该是对象而不是数组 (2认同)