在 React 中,useReducer 作为 useState 的替代方案,可用于复杂逻辑场景中的状态管理, 在代码的写法上和 Redux 类似。而 Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树的逐层传递 props。
在 React 16.3 正式推出 Context 时,有一些人认为 Context 将会取代 Redux,其实两者的功能存在差异:Context 不是状态管理工具,它只是支持了组件间的数据共享。但是,在实践中配合使用 Context 和 useState/useReducer,可实现一种简单的全局状态管理。
useReducer 简单介绍
useReducer 可以看作是 useState 的另外一种形式,两者的功能是基本一致,而写法则与 Redux 相同。
const initialState = { count: 0 };
const reducer = (state, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div onClick={() => dispatch({ type: "increment" })}>{state.count}</div>
);
};
Context 简单介绍
当组件嵌套层次太深时,层层透传 props 比较麻烦,而 Context 可以解决这个问题。
const Context = React.createContext();
const Counter = () => {
const { count, add } = useContext(Context);
return <div onClick={() => add()}>{count}</div>;
};
const App = () => {
const [count, setCount] = useState(0);
const add = useCallback(() => setCount(count + 1), [count])
const value = useMemo(() => ({
count,
add
}), [count, add])
return (
<Context.Provider value={value}>
<Counter />
</Context.Provider>
);
};
使用 Context 之后,Counter 就能访问到 App 的状态数据 count,这里的 count 可以看作是一个全局状态。Context 作为一个桥梁,能让内部的组件访问到外层组件的状态数据,而状态管理是由 useState/useReducer 完成的。接下来,用 useReducer 做一下改造:
const initialState = { count: 0 };
const reducer = (state, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
};
const ReducerContext = React.createContext();
const ReducerProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const store = useMemo(() => {
return [state, dispatch];
}, [state]);
return (
<ReducerContext.Provider value={store}>{children}</ReducerContext.Provider>
);
};
const useReducerContext = () => {
return useContext(ReducerContext);
};
const Counter = () => {
const [state, dispatch] = useReducerContext();
return (
<div onClick={() => dispatch({ type: "increment" })}>{state.count}</div>
);
};
const App = () => {
return (
<ReducerProvider>
<Counter />
</ReducerProvider>
);
};
这种 Context + useReducer 实现的状态管理,虽然在写法上与 React-Redux 类似,但是两者还是存在一定的差异:
-
两者都依赖于 Context 传值,但传值的内容存在差异,Context + useReducer 传的是当前的 state 值,React-Redux 传的是当前 Redux store 的实例
-
Context + useReducer state 发生变化时,所有订阅它的组件都会被强制重新渲染,即便该组件使用的是 state 中的部分数据;React-Redux 支持组件订阅 store 中的更细颗粒度的数据,只有订阅的那部分数据更新了,组件才会重新渲染。
-
在使用场景上,Context + useReducer 适用于中等复杂场景的状态管理,可以避免状态在组件间层层透传;React-Redux 适合更复杂的应用场景,并且支持使用一些中间件。
原文始发于微信公众号(KooFE前端团队):使用 Context + useReducer 实现 React 全局状态管理
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/54293.html