• Redux 学习笔记


    在使用 React Redux 前,我们首先了解一下 Redux 的一些基础知识。

    Redux 是 JavaScript 应用程序中用于状态管理的容器。它不依赖于任何框架,可以与任何 UI 库和框架一起使用。在应用程序中使用 Redux 时,Redux 是以可预测的方式管理状态。

    Redux 的核心概念

    1. Store

    应用系统中需要管理的数据,全部集中在这里

    1. Action

    数据的处理都存放在这里,例如数据的添加、删除操作等

    1. Reducer

    数据接收和转换存放在这里

    Store、Action 和 Reducer 的三者关系

    在这里插入图片描述

    Redux 的使用原则

    1. 应用程序的状态存储形式是单个对象树

    2. 状态的获取必须通过Action来执行,在Action中我们存放着对应很多动作的key,我们只有执行对应的动作后才能拿到数据

    3. 拿到的数据必须通过Reducer来转换状态树的数据,而Reducer在执行时会拿到Action对应的动作,并接受返回的数据然后进行处理

    Actions 说明

    Action 的创建如下:

    // 定义一个action
    function buyCake() {
      return {
        type: BUY_CAKE,
        info: "First redux action",
      };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    从上述的创建过程来看,action 其实是一个函数并且返回一个对象,其中返回的对象必须带有type属性,这个属性在后续调用的时候会用到。

    其次就是除了type属性外,我们还可以根据自己的业务需求来扩展action的属性。

    Reducers 说明

    Reducers 是专门负责接受状态并且执行对应的action,并把执行完成后跟新对应的状态。

    定义一个 Reducer 的过程很简单,具体代码如下:

    // 定义一个 state
    const initialState = {
      numOfCakes: 20,
    };
    
    // 定义一个 reducer
    const reducer = (state = initialState, action) => {
      switch (action.type) {
        case BUY_CAKE:
          return {
            numOfCakes: state.numOfCakes - 1,
          };
    
        default:
          return state;
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    从上述的代码中可以看出Reducer本质也是一个函数,并且接受两个函数。其中第一个参数是Store,而第二个参数是action,并且通过 type 来决定对状态执行什么操作。

    Store 说明

    Store 的职责主要包括如下几点:

    1. 负责保存应用程序状态
    2. 对外暴露getState的方法,通过此方法可以获取到应用程序中的状态值
    3. 提供了一个dispatch(action)的方法,主要是用于调度对应的action,从而修改状态值
    4. 提供了一个注册监听器的方法subscribe(listener),每当状态发生改变的时候都会触发此函数
    5. 提供了一个取消监听器的方法,用于收回已注册的监听器

    实现Store的过程如下:

    const redux = require("redux");
    const createStoreFn = redux.createStore; // 已经过时,这里只是展示概念性的东西,所以采用了旧方法
    const store = createStoreFn(reducer); // 管理对应的状态
    console.log(store.getState()); // 使用对外暴露获取状态数据的方法
    
    // 注册监听器
    const unsubscribe = store.subscribe(() =>
      console.log("update state", store.getState())
    );
    
    // 调用对应的 action 方法
    store.dispatch(buyCake());
    store.dispatch(buyCake());
    store.dispatch(buyCake());
    
    unsubscribe();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如何实现多个 Reducers

    只用一个 Reducers 来管理状态

    function buyIceCream() {
      return {
        type: BUY_ICECREAM,
      };
    }
    
    // 定义一个 State
    const initialState = {
      numOfCakes: 20,
      numOfIceCream: 20,
    };
    
    // 定义一个 reducer
    const reducer = (state = initialState, action) => {
      switch (action.type) {
        case BUY_CAKE:
          return {
            ...state,
            numOfCakes: state.numOfCakes - 1,
          };
        case BUY_ICECREAM:
          return {
            ...state,
            numOfIceCream: state.numOfIceCream - 1,
          };
        default:
          return state;
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    通过上述的实例代码可以看出,我们只是简单的添加了一个actionReducer就需要添加一个对应的状态处理方法,假如我们的业务逻辑比较复杂的话Reducer则会变得非常难以维护,所以我们可以使用多个Reducer来分解对状态处理的方法。

    实现多个 Reducers

    在实现多个 Reducers 的时候,我们需要用到combineReducers来帮我们注册对应的Rducer。具体的代码实例如下:

    const initialCakeState = {
      numOfCakes: 20,
    };
    const initialIceCreamState = {
      numOfIceCream: 20,
    };
    
    const cakeReducer = (state = initialCakeState, action) => {
      switch (action.type) {
        case BUY_CAKE:
          return {
            ...state,
            numOfCakes: state.numOfCakes - 1,
          };
        default:
          return state;
      }
    };
    
    const iceCreamReducer = (state = initialIceCreamState, action) => {
      switch (action.type) {
        case BUY_ICECREAM:
          return {
            ...state,
            numOfIceCream: state.numOfIceCream - 1,
          };
        default:
          return state;
      }
    };
    
    const rootReducer = combineReducers({
      cake: cakeReducer,
      iceCream: iceCreamReducer,
    });
    const store = createStoreFn(rootReducer);
    const unsubscribe = store.subscribe(() =>
      console.log("update state", store.getState())
    );
    console.log(store.getState());
    
    // 调用对应的 action 方法
    store.dispatch(buyCake());
    store.dispatch(buyCake());
    store.dispatch(buyCake());
    
    store.dispatch(buyIceCream());
    store.dispatch(buyIceCream());
    
    unsubscribe();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    如何实现异步 Actions

    上述的操作都是同步的,而接下来我们来实现一下异步的Actions

    我们以获取用户列表数据为例一步一步实现异步 Actions。

    1. 定义State

    因为要实现异步的 Actions,所以我们的数据获取和处理会有一定处理时间,所以对应的State属性应该包括如下几个属性:loadinguserserror。具体代码如下:

    const initialState = {
      loading: false, // 判断是否已经获取到数据
      users: [],
      error: "",
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 实现对应的 Actions

    有了对应的状态数据,我们就可以编写一些对应的 Action 功能。具体的实例代码如下:

    const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
    const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
    const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
    
    const fetchUsersRequest = () => {
      return {
        type: FETCH_USERS_REQUEST,
      };
    };
    
    const fetchUserSuccess = (users) => {
      return {
        type: FETCH_USERS_SUCCESS,
        payload: users,
      };
    };
    
    const fetchUserFaikuer = (error) => {
      return {
        type: FETCH_USERS_FAILURE,
        payload: error,
      };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. 实现对应的 Reducer

    有了状态和执行动作,我们就可以实现对应的 Reducer。具体的代码如下:

    const reducer = (state = initialState, action) => {
      switch (action.type) {
        case FETCH_USERS_REQUEST:
          return {
            ...state,
            lading: true,
          };
        case FETCH_USERS_SUCCESS:
          return {
            loading: false,
            users: action.payload,
            error: "",
          };
        case FETCH_USERS_FAILURE:
          return {
            loading: false,
            users: [],
            error: action.payload,
          };
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    1. StateActionsReducer建立关系

    有了上述的准备,现在我们就可以把这三个元素建立关系。

    在建立关系之前我们需要安装两个工具:

    npm install axios redux-thunk
    
    • 1

    我们使用 redux 的中间件来实现异步的数据获取。具体代码如下:

    const appluMiddleware = redux.applyMiddleware;
    const thunkMiddleware = require("redux-thunk").default;
    const axios = require("axios");
    
    const store = createStoreFn(reducer, appluMiddleware(thunkMiddleware));
    
    const fetchUsers = () => {
      return function (dispatch) {
        dispatch(fetchUsersRequest());
        axios
          .get("https://jsonplaceholder.typicode.com/users")
          .then((response) => {
            console.log(response);
            const users = response.data.map((user) => user.id);
            dispatch(fetchUserSuccess(users));
          })
          .catch((error) => {
            dispatch(fetchUserFaikuer(error.message));
          });
      };
    };
    
    store.subscribe(() => {
      console.log(store.getState());
    });
    store.dispatch(fetchUsers());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    什么是单片机最小系统?
    编写程序,建立一动态链表,其中包含学生学号,姓名,年龄,输入一个学生学号删除相对应的节点
    【mongoDB】
    Gateway网关
    C++对string进行大小写转换的三种方法
    代码阅读工具推荐understand
    !与~有什么区别
    线性表
    CSDN一站式云服务开放内测,诚邀C站新老用户来抢鲜
    从Systrace看抖音Android Camera Bufferqueue渲染
  • 原文地址:https://blog.csdn.net/qq_33003143/article/details/133944245