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