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

Does putting state and dispatch into separate context providers prevent unnecessary re-renders?

我发现在 official next.js examplestatedispatch 中将信息放在单独的上下文提供程序中。

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

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)

如果几乎所有组件都使用状态和分派,则无需将它们放在单独的 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>
  )
}

编辑:

正如@dciccale 在评论中指出的那样,如果您的应用程序中有相当多的组件主要只使用调度,那么将调度和状态保持在不同的上下文中很有意义,因此它们不会重新调用-如果状态改变则渲染。

即使我们用 useMemo hook 记住了 contextValue,每次更新 state 的值时,contextValue 仍然会重新计算,导致所有依赖于上下文的组件重新渲染,甚至其中一些只依赖于 dispatch only.

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

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