onistbin/blog

Redux详解

Opened this issue · 0 comments

Redux是什么:

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

  这句话包含以下几点涵义:

  • 状态容器: 整个应用的 state 被储存在一棵 Object Tree 中,而且这个Object Tree 只存在于唯一一个 store 中。store是应用程序领域(app domain)的状态集合,一个应用程序只有一个store(Flux中允许有多个Store)。

  • JavaScript应用: Redux并不是只服务于react应用,是独立的一个库,可用于各种JavaScript应用。

  • 可预测化: 可预测的(predictable): 因为Redux用了reducer与纯函数(pure function)的概念,每个新的state都会由旧的state建来一个全新的state,所有的状态修改都是"可预测的"。



Redux要解决的问题是什么:

  JavaScript 单页应用开发越来越复杂,JavaScript 需要管理更多的状态(state)。这些状态可能是接口数据、缓存数据、mock数据、UI状态等。随着应用的变得复杂,而且随着代码量越来越大,管理不断变化的state非常困难。如果一个UI的改变,会引起一个model或者多个model的改变。亦或者一个model的改变引起另一个model或者多个model的改变时。当需要增加一个功能的时候,我们很难追踪到底发生了什么。系统会变得很难维护。Redux的出现就是为了解决 state 里的数据问题。
  Redux让每个 state 变化都是可预测的,将应用中所有的动作与状态都统一管理,让一切有据可循。



Redux核心设计理念

Redux有三大原则

  • 单一数据源: 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
  • state 是只读的,唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
  • 使用纯函数来执行修改,为了描述 action 如何改变 state tree ,你需要编写 Reducer。Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。


Redux认为:

  1. Web应用是一个状态机,视图与状态是一一对应的。

view-state

  2. 所有的状态,保存在一个对象里面。




Redux介绍

Action

  Action是通知,一般由View发出,告知Store应该发生变化。Action是一个对象,其中type属性是必须的,可以附带一些负载属性。

        const action = {
            type: 'ADD_USER',
            name: '尖冰'
        };

Reducer

  Store收到 Action后,必须计算出一个新的State,这个计算过程称为Reducer 。 Reducer是一个函数,接受Action和当前状态作为参数,返回一个新的State。

        const reducer = (state = 0, action) => {
            switch (action.type) {
                case 'ADD_USER':
                    return [action.name, ...state];
                default: 
                    return state;
            }
        };

        const state = createStore(reducer);

  Reducer是一个纯函数,即只要拥有相同的输入,必得到相同的输出 .
  不要在Reducer中做以下操作:

  • 修改传入参数
  • 执行有副作用的操作,如 API 请求和路由跳转
  • 调用非纯函数,如 Date.now() 或 Math.random()

combineReducers

  一个应用可能包含有多个Reducer,每个Reducer只负责处理它管理的那部分State,那么最后多个Reducer怎么合并为一个reducers呢?Redux提供了combineReducers这个方法。该方法会将多个Reducer合并为一个reducers。

/**
* 添加用户 reducer
* @param {*} state 
* @param {*} action 
*/
let addUser = (state = [], action) => {
   switch (action.type) {
     
   	case 'ADD_USER':
   		return [action.name, ...state];
   	default:
   		return state;
   }
}


/**
* 编辑用户 reducer
* @param {*} state 
* @param {*} action 
*/
let  editUser = (state = {}, action) => state;


/**
* 合并为一个 reducer
* @param {*} state 
* @param {*} action 
*/
let reducers = combineReducers({addUser, editUser});

Store

  Store负责联系action和reducer,一个应用只能有一个Store。

Store有以下职责:

  • 维持应用的 state;
  • 提供 getState() 方法获取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通过 subscribe(listener) 注册监听器;
  • 通过 subscribe(listener) 返回的函数注销监听器。
        import { createStore } from 'redux'
        const store = createStore(reducer);
        store.subscribe(render);
        store.dispatch({ 
            type: 'ADD_USER',
            name: '尖冰'
        })

Store方法

        Store = { 
            dispatch: Dispatch      // 发送 action 时使用
            getState: () => State   // 获取当前 state
            subscribe: (listener: () => void) => () => void // 注册回调,state有更动时调用
            replaceReducer: (reducer: Reducer) => void  //动态加载其它的reducer
        }



Redux使用步骤

  1. 从redux模块中汇入createStore方法
        import { createStore } from 'redux'
  1. 写一个reducer
        function addUser(state = [], action) {
            switch (action.type) {
                
                case 'ADD_USER':
                    return [action.name, ...state];
                default:
                    return state;
            }
        }
  1. 由写好的reducer,创建出 store
        const store = createStore(reducer);
  1. render方法,如果有状态改变,重新render
        function render() {
            const data = store.getState();
            data.map(() => {
                ...
            });
        }
  1. 首次调用 render
        render();
  1. 订阅 render 函数到 store , store.subscribe(render)
        store.subscribe(render);
  1. 触发事件调用store.dispatch(action)
        store.dispatch({ 
            type: 'ADD_USER',
            name: '尖冰'
        })


工作流程总结

工作流程

第一步,发出Action

store.dispatch(action);

第二步,Store 自动调用 Reducer,并且传入两个参数,旧的Store以及Action.

let nextStare = addUser(previousState, action);

第三步,State发生变化,Store 就会调用注册函数

store.subscribe(listener);

第四步,listener可以通过store.getState()得到当前状态。调用render重新渲染。