将 Context 拆分为状态并更新以提高性能(减少渲染)?

Split up Context into state and update to improve performance (reduce renders)?

一些博客文章在使用 React 上下文 时将上下文拆分为 两个 单独的更新和状态上下文。我想知道这是否真的会提高性能或会导致减少渲染周期。

所以最终的解决方案将有:

拆分 UpdateState 上下文的解决方案:

const authContext = React.createContext<AuthUser | null | undefined>(undefined)
const authUpdateContext = React.createContext<Dispatch<SetStateAction<AuthUser | null>> | null>(null)

export function useAuth() {
    const authUser = React.useContext(authContext);
    if (authUser === undefined) throw new Error(`useAuth must be used within a ContextAuthProvider`);
    return authUser;
}

export const useAuthUpdate = () => {
    const setAuthUser = React.useContext(authUpdateContext);
    if (!setAuthUser) throw new Error(`useAuthUpdate must be used within a AuthProvider`);
    return setAuthuser;
}

export const AuthProvider: React.FC = ({children}) => {
    const [authUser, setAuthUser] = useState<AuthUser | null>(null)
    return (
        <authUpdateContext.Provider value={setAuthUser}>
            <authContext.Provider value={authUser}>
                {children}
            </authContext.Provider>
        </authUpdateContext.Provider>
    )
}

// Usage only in components where needed (one of those two or both combined)
const authUpdate = useAuthUpdate()
const auth = useAuth()

您需要了解的重要一点是,当上下文的值发生变化时,订阅特定上下文的任何组件都会重新呈现。 回到你的问题,使用不同的钩子来更新和检索状态值没有意义,因为两者都连接到上下文提供者。我希望这是有道理的。更多详情 here

上下文的动作往往不会改变,而那些动作控制的状态却会改变。如果您创建一个同时提供状态值和状态更新方法的上下文,则每次状态值更改时,都会在订阅上下文的所有组件上触发渲染,即使它们只访问操作(可能没有更改) .

您可以通过将上下文拆分为两个单独的上下文来避免这种情况,并在仅订阅操作上下文的组件上保存渲染(以及相关的副作用,例如 useEffect() 调用)。

这是一个相关问题:Avoid runnning an effect hook when Context get updated 清楚地说明了这一点。如果在该示例中只使用了一个上下文,则 ActionsComponent 中的 useEffect 将在 ValueComponent 中的计数器的每个滴答时触发,但它不会因为每个组件都订阅了不同的上下文。

这里是 React 存储库上的一个问题中您的选项的简要概述:Preventing rerenders with React.memo and useContext hook。 #15156:Option 1 (Preferred): Split contexts that don't change together