使用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

相关文章
相关标签/搜索