Redux 学习

Redux 是 JavaScript 的状态容器,提供可预测的状态管理。

概念和 API

store

store 是 redux 保存数据的地方,通俗的来说就是一个仓库。整个应用里面只能有一个 store

  • redux里面提供了一个创建store的 APIcreateStore

    import { createStore } from 'redux'
    const store = createStore(...)
    const state = store.getState()
    
  • 提供一个获取state的方法

  • 提供一个dispatch的方法更新state

  • 通过 subscribe(listener) 注册监听器

Action

本质上就是一个普通的 js 对象,但是 action 里面必须有一个 type 字段,表示执行的动作

const action = {
  type: "ADD_TODO",
  payload: "zhangnuli"
};
  • Action Creator

  • 视图层要发送多少种消息,就有多少种 action,可以定义一个函数生成 Action。

  • const ADD_TODO = "添加 TODO";
    
    function actionCreator(text) {
      return {
        type: ADD_TODO,
        text
      };
    }
    
    const action = addTodo("Learn Redux");
    
  • store.subscribe(),一旦 state 发生变化,就会执行这个函数

    import { createStore } from "redux";
    const store = createStore(reducer);
    
    store.subscribe(listener);
    

派发 action,是让 store 里面的数据发生改变的唯一途径。

import { createStore } from 'redux'
let store = createStore(...)

function addTodo(text) {
  return {
    type: 'ADD_TODO',
    text
  }
}

store.dispatch(addTodo('Read the docs'))

Reducer

store 收到 action 后,必须需要给出一个新的 state,这样才会出发视图层的变化。这种计算的过程叫做 Reducer。Reducer 是一个函数,接收 action 和 state 作为参数,返回一个新的 state

const reducer = function(state, action) {
  // ...
  return new_state;
};
  • 在整个 应用中,我们可以给一个 state 的默认值
const defaultState = 0;
const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case "ADD":
      return state + action.payload;
    default:
      return state;
  }
};

const state = reducer(1, {
  type: "ADD",
  payload: 2
});
  • reducer 是一个纯函数,reducer 不能改变 state,必须返回一个新的 state
switch (action.type) {
  case SET_VISIBILITY_FILTER:
    return Object.assign({}, state, {
      visibilityFilter: action.filter
    });
  case ADD_TODO:
    return Object.assign({}, state, {
      todos: [
        ...state.todos,
        {
          text: action.text,
          completed: false
        }
      ]
    });
  default:
    return state;
}

Reducer 的拆分

Reducer 函数负责生成 State。由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。

  • 没拆分之前的 reducer

    function todoApp(state = initialState, action) {
      switch (action.type) {
        case SET_VISIBILITY_FILTER:
          return Object.assign({}, state, {
            visibilityFilter: action.filter
          });
        case ADD_TODO:
          return Object.assign({}, state, {
            todos: [
              ...state.todos,
              {
                text: action.text,
                completed: false
              }
            ]
          });
        case TOGGLE_TODO:
          return Object.assign({}, state, {
            todos: state.todos.map((todo, index) => {
              if (index === action.index) {
                return Object.assign({}, todo, {
                  completed: !todo.completed
                });
              }
              return todo;
            })
          });
        default:
          return state;
      }
    }
    
  • 拆分之后的 reducer

    function todos(state = [], action) {
      switch (action.type) {
        case ADD_TODO:
          return [
            ...state,
            {
              text: action.text,
              completed: false
            }
          ];
        case TOGGLE_TODO:
          return state.map((todo, index) => {
            if (index === action.index) {
              return Object.assign({}, todo, {
                completed: !todo.completed
              });
            }
            return todo;
          });
        default:
          return state;
      }
    }
    
    function todoApp(state = initialState, action) {
      switch (action.type) {
        case SET_VISIBILITY_FILTER:
          return Object.assign({}, state, {
            visibilityFilter: action.filter
          });
        case ADD_TODO:
          return Object.assign({}, state, {
            todos: todos(state.todos, action)
          });
        case TOGGLE_TODO:
          return Object.assign({}, state, {
            todos: todos(state.todos, action)
          });
        default:
          return state;
      }
    }
    

在上面的代码中,把 reducer 进行了拆分,变成了独立的一个函数。Redux 提供了一个combineReducers()方法,用于合并拆分的 reducer

import { combineReducers } from "redux";
import * as reducers from "./reducers";

const todoApp = combineReducers(reducers);