Redux is a predictable state container for JavaScript apps.css
原文地址:使用React Hook实现Redux状态机html
本文的代码能够在CodeSandbox中查看。react
Redux是React常常用到的一个数据状态管理器(状态机),它将应用中全部的数据(state)以对象树的形式存储在store中,经过触发action来改变state,而描绘改变规则须要编写reducer。git
由于Redux不单单是为React编写的,因此在React中经常会用到React-Redux来一同使用。React-Redux使用两个主要的API,分为叫作Provider
和connect
来提高Redux开发效率和体验。github
在React 16.8以前,为了实现统一的状态机,最好的方法就是使用Redux了。不过,React 16.8中Hook API新增的useContext
和useReducer
可以让咱们本身实现一个具有Redux核心功能的状态机。json
咱们先看一下Redux的三个基本原则是什么:redux
咱们遵循这三个基本原则来开发咱们本身的状态机,其实查看useReducer
的用法就知道它已经知足了原则2和3bash
const [state, dispatch] = useReducer(reducer, initialArg, init);
app
因此,咱们结合官网的例子来编写state和reducer。dom
文件目录以下所示:
public
src
reducer
index.js
index.js
style.css
package.json
复制代码
在reducer文件夹的index.js文件中,编写initialState
和reducer
:
export const initialState = { count: 0 };
export function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
}
复制代码
而后在src/index.js中生成一个store
,只在顶层组件中建立一个store
是为了符合原则1。
import { reducer, initialState } from "./reducer";
const store = useReducer(reducer, initialState);
复制代码
能够看到应用useReducer
很简单的就建立了一个符合Redux三个基本原则的状态机,而后咱们就要考虑如何将store状态传递到更深层次的组件中。在Redux中咱们使用subscribe
方法去订阅状态,而使用React-Redux能够将store
像props同样传值给子组件,这样就不须要每次都去订阅。因此,接下来咱们使用React中的Context API来实现状态的传递。
在src/index.js中建立一个AppContext
,初始值为空:
const AppContext = createContext({});
const { Provider } = AppContext;
复制代码
而后在顶层组件App
中使用:
function App() {
const store = useReducer(reducer, initialState);
return (
<Provider value={store}> <div className="App"> <TopNavBar /> </div> </Provider>
);
}
复制代码
这样不管多深的组件都可以获取到store
存储的数据状态,并且可以获取到dispatch
方法来改变state
。这里React的另外一个Hook就要发挥实力了,那就是useContext
,它能够接收一个context对象(React.createContext的返回值)并返回该context的当前值。
function TopNavBar() {
const value = useContext(AppContext);
const [state] = value; // 这里的value就是useReducer建立的store
const { count } = state;
return (
<> <p>{count}</p> <Button /> </> ); } 复制代码
在Button
组件中使用useContext
获取dispatch
来经过触发一个action
来改变count
的值:
function Button() {
const value = useContext(AppContext);
const [state, dispatch] = value;
return (
<div className="button-wrapper"> <button type="button" onClick={() => dispatch({ type: "increment" })}> Plus </button> <button type="button" onClick={() => dispatch({ type: "decrement" })}> Minus </button> </div>
);
}
复制代码
这样一个知足Redux的三个原则,同时具有React-Redux部分功能的简洁版状态机就完成了。在一些不须要管理过多复杂状态的应用中咱们就可使用这样的方式来本身建立状态机,固然,咱们还有像effect、connect和middleware这样的功能没有彻底实现,可是在准备使用他们以前,先得思考如下,是否真的须要。
Brevity is the soul of wisdom. Tediousness is the limbs and outward flourishes.
—— William Shakespeare