将状态和分派放入单独的上下文提供程序是否可以防止不必要的重新渲染?

Nel*_*Luk 3 reactjs next.js react-context use-reducer context-api

我在官方的 next.js 示例中发现了这一点state并且dispatch将信息放在了单独的上下文提供程序中。

这样做的意义何在?这种做法是否可以防止不必要的重新渲染?

export const CounterProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, 0)
  return (
    <CounterDispatchContext.Provider value={dispatch}>
      <CounterStateContext.Provider value={state}>
        {children}
      </CounterStateContext.Provider>
    </CounterDispatchContext.Provider>
  )
}

export const useCount = () => useContext(CounterStateContext)
export const useDispatchCount = () => useContext(CounterDispatchContext)
Run Code Online (Sandbox Code Playgroud)

Shu*_*tri 5

如果几乎所有组件都同时使用状态和分派,则不需要将它们放在单独的 ContextProvider 中,只需确保在将它们作为对象传递时记住传递给提供程序值的参数。这样你的消费者只会在状态实际改变时重新渲染。还要注意,dispatch实例实际上并没有改变,所以没有必要为它创建一个单独的上下文

export const CounterProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, 0)
  const contextValue = useMemo(() => ({state, dispatch}), [state, dispatch])
  return (
    <CounterContext.Provider value={contextValue}>
        {children}
    </CounterContext.Provider>
  )
}
Run Code Online (Sandbox Code Playgroud)

编辑:

正如@dcccale 在评论中指出的那样,如果您的应用程序中有很多组件在很大程度上只使用 dispatch 并且因此它们不会在状态更改时重新渲染,那么将 dispatch 和 state 保持在单独的上下文中是很有意义的.

即使我们contextValue用 useMemo hook记忆,contextValue每次更新state的值仍然会被重新评估,导致所有依赖于上下文的组件重新渲染,甚至其中一些只依赖于dispatchonly。

另见:https : //hswolff.com/blog/how-to-usecontext-with-usereducer/#performance-concerns

评估您的应用要求并明智地做出决定。

  • 我认为为状态和调度创建单独的上下文提供程序确实会产生影响。如果您的子组件*仅*需要调度函数,而不需要状态,那么如果提供程序的状态发生更改,这些组件也将重新渲染。但是,如果有单独的上下文提供程序,一个用于状态,一个用于调度,则仅使用调度的子组件在状态更改时不需要重新渲染。 (4认同)
  • 当上下文存储广泛不同事物的信息时,分离上下文是有好处的,在上述情况下,它不是必需的并且用于非特殊目的 (2认同)