发布于 2026-01-06 2 阅读
0

用 React Contexts 替换 Redux

用 React Contexts 替换 Redux

在我目前的项目中,我们过去常常使用Redux来实现用户身份验证、语言偏好设置、视口宽度以及在组件树深处共享状态等功能。

很久以前,我们就开始用上下文替换共享状态,因为这样更容易提供和管理仅限于应用程序特定部分的状态。这样一来,状态就不会向上泄漏,也就是说,登录页面不需要访问待办事项列表。

举个实际例子,只保留相关部分:

type SetLanguageAction = {
    type: 'SET_LANGUAGE'
    language: string
}

const language = (
    state: string = initialLanguage,
    action: SetLanguageAction
) => {
    if (action.type !== 'SET_LANGUAGE') {
        return state
    }

    localStorage.set('language', action.language)
    return action.language
}

// plus boilerplate to attach it to the store
Enter fullscreen mode Exit fullscreen mode

结合上下文,它就变成了:

import React from 'react'

const Context = React.createContext({} as {
    language: string
    setLanguage: React.Dispatch<React.SetStateAction<string>>
})

const LanguageProvider: React.FC = ({ children }) => {
    const [language, setLanguage] = useLocalStorage('language', initialLanguage)

    return (
        <Context.Provider value={{ language, setLanguage }}>
            {children}
        </Context.Provider>
    )
}

const useLanguage = () => React.useContext(Context)
// and that's it!
Enter fullscreen mode Exit fullscreen mode

你看,所有行为都包含在一个文件中,而不是像 Redux 那样分散在多个文件中(你需要将actions.ts所有reducers.ts内容粘合在一起)。

此外,由于 Provider 本身就是 React 组件,因此您可以充分利用React Hooks 的功能。例如,我可以useLocalStorage通过react-use访问本地存储,而无需手动处理。

它有助于隔离行为,也有助于实现更严格的类型定义。在用户身份验证中,如果用户状态位于全局状态中,则其类型为 `<global state>` User | null,因为用户数据是在从后端加载数据后初始化的。

有了本地化上下文,就可以做到这一点,User而且我们无需检查是否为空或!在访问 store 后执行任何操作,因为我可以在等待数据加载时暂停渲染(例如)。它与SWRif (!user) return null配合得非常好:)

封面图片由 Timothy Meinberg 提供(参见 Unsplash)。

文章来源:https://dev.to/rsa/replacing-redux-with-react-contexts-1hj8