使用React Hook實現Redux狀態機

Redux is a predictable state container for JavaScript apps.css

原文地址:使用React Hook實現Redux狀態機html

本文的代碼能夠在CodeSandbox中查看。react

Redux是React常常用到的一個數據狀態管理器(狀態機),它將應用中全部的數據(state)以對象樹的形式存儲在store中,經過觸發action來改變state,而描繪改變規則須要編寫reducergit

由於Redux不單單是爲React編寫的,因此在React中經常會用到React-Redux來一同使用。React-Redux使用兩個主要的API,分爲叫作Providerconnect來提高Redux開發效率和體驗。github

在React 16.8以前,爲了實現統一的狀態機,最好的方法就是使用Redux了。不過,React 16.8中Hook API新增的useContextuseReducer可以讓咱們本身實現一個具有Redux核心功能的狀態機。json

咱們先看一下Redux的三個基本原則是什麼:redux

  1. 單一數據源 - 整個應用程序的state存儲在單個store的對象樹中
  2. state爲只讀 - 改變state的惟一方法是觸發一個action
  3. 使用純函數來修改 - 爲了描述actions是如何修改state,你須要編寫reducers

咱們遵循這三個基本原則來開發咱們本身的狀態機,其實查看useReducer的用法就知道它已經知足了原則2和3bash

const [state, dispatch] = useReducer(reducer, initialArg, init);app

因此,咱們結合官網的例子來編寫statereducerdom

文件目錄以下所示:

public
src
  reducer
    index.js
  index.js
  style.css
package.json
複製代碼

在reducer文件夾的index.js文件中,編寫initialStatereducer

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部分功能的簡潔版狀態機就完成了。在一些不須要管理過多複雜狀態的應用中咱們就可使用這樣的方式來本身建立狀態機,固然,咱們還有像effectconnectmiddleware這樣的功能沒有徹底實現,可是在準備使用他們以前,先得思考如下,是否真的須要。

Brevity is the soul of wisdom. Tediousness is the limbs and outward flourishes.

—— William Shakespeare

相關文章
相關標籤/搜索