用 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
结合上下文,它就变成了:
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!
你看,所有行为都包含在一个文件中,而不是像 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