Redux

Redux是一个状态管理库,一般用于大型应用中。它出现的原因是,应用越来越复杂, 通过状态提升已经不能满足应用的需求。

1. Redux设计思想

1. 将整个应用的状态state(一个状态树)存在一个仓库中,唯一一个store中。

2. 组件通过store的dispatch方法,派发动作action到store中。

3.store通过唯一的一个根reducer,根据原始state和action,产生新的状态。

4. 其他组件可以订阅store中状态值的变化,用于刷新组件

2. createStore

该方法用于创建仓库

const store = createStore(reducer[, initState]);

1. 参数

reducer是处理器函数。initState是仓库的初始状态。

1) 在创建store时赋初值,本质上相当于给reducer函数中的传入state参数为initState。

2)initState省略时, 还可以通过reducer函数的state参数赋初值。

redux会在创建仓库的时候调用一次dispatch,触发自身定义的@@redux/INIT动作。然后获取之后的state值。

2. dispatch

dispath函数接受一个含有type属性的纯对象进行派发动作,最后返回动作本身。

  function dispatch(action) {
    // 提示必须是纯对象
    if(!isPlainObject(action)) {
      throw new Error('必须是纯对象');
    }
    // 提示不能是undefined
    if (typeof action === 'undefined') {
      throw new Error('type不能是undefined')
    }
    currentState = currentReducer(currentState, action);
    for(let i=0; i < listeners.length; i++) {
      listeners[i]();
    }
    // 注意dispatch返回的是action
    return action;
  }

  /****调用后返回action本身****/
  const result = store.dispatch({type: types.INCREASE }); 
  console.log(result); //{type: "INCREASE" }

3. subscribe/unsubscribe

// 监听函数render1订阅store的状态变化
const unscribe = store.subscribe(render1);

// 运行返回值,取消订阅
unscribe();

订阅函数本身只是将监听函数加入队列,监听函数的执行在dispatch方法调用时。

  function subscribe(listenr) {
    listeners.push(listenr);
    return function() { // 取消订阅实际是将监听函数移除监听队列
      const index = listeners.indexOf(listenr);
      listeners.splice(index, 1);
    }
  }

开发中我们要实时刷新页面,需要依靠渲染函数取订阅(subscribe)store的变化。

  componentWillUnmount() {
    this.unsubcribe();
  }
  
  componentDidMount() {
    this.unsubcribe = store.subscribe(() => {
      this.setState({
        number: store.getState()
      })
    })
  }

4. store.getState()

获取仓库当前的状态。第一次获取时,有两个地方可以赋初值。

3. bindActionCreators

将动作生成函数绑定dispatch方法。从而可以直接调用actionCreator方法。

function bindActionCreator(action, dispath) {
  return function() {
    return dispath(action.apply(this, arguments))
  }
}

export default function(actions, dispath) {
  if(typeof actions === 'function') {
    return bindActionCreator(actions, dispath);
  }
  const bondActionCreators = {};
  for(let key in actions) {
    bondActionCreators[key] = bindActionCreator(actions[key], dispath)
  }
  return bondActionCreators;
}

使用时:

import actions from '../store/actions';
import store from '../store';
import {bindActionCreators} from '../redux';
const bondActions = bindActionCreators(actions, store.dispatch);

<button onClick={bondActions.increase}>+</button>
<button onClick={bondActions.decrease}>-</button>

4. combineReducers

当应用中模块过多,使用一个reducer函数很难处理时,可以写多个reducer,然后通过该方法合并成一个根reducer。

本质上,是遍历所有的reducer处理状态树,然后返回新的状态。

export default function(reducers) {
  // 返回一个根reducer,且该reducer返回最新的state树
  return function(state={}, action) { 
    const nextState =  {};
    const previousState = state;
    // 获取各个子reducer的key值
    const reducerKeys = Object.keys(reducers);
    // 遍历reduers
    for(let i=0; i< reducerKeys.length; i++) {
      const key = reducerKeys[i];
      nextState[key] = reducers[key](previousState[key], action)
    }
    return nextState;
  }
}

 5. applyMiddleware

用于向仓库应用中间件。而中间是用于拦截并改写dispatch方法。有两种用法:

1) 级联调用,这样的好处是每个方法中传参可以不固定

let store = applyMiddleware(logger, xx, xx)(createStore)(reducer, initState);

2)中间的参数可以省略

let store = createStore(reducer, initState, applyMiddleware(logger, xxx))

原理

从最后一个中间件开始执行,返回的结果(处理过的dispatch)作为倒数第二个的dispatch参数,依此类推。

中间件

中间件的通用写法是:

let middleware = store => dispatch => action => {
    // TODO
}
原文地址:https://www.cnblogs.com/lyraLee/p/12072641.html