zoukankan      html  css  js  c++  java
  • 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
    }
  • 相关阅读:
    [杭电_HDU] 2013
    动态调整线程数的python爬虫代码分享
    wampserver 配置的几个坑(雾
    wampserver apache 403无权限访问 You don't have permission to access /index.html on this server
    [爬坑日记] 安卓模拟器1903蓝屏 没开hyper-v
    [单片机] ESP8266 开机自动透传
    [操作系统] 死锁预防和死锁避免
    [linux] 手机Deploy linux 桌面中文乱码
    XHTML基础
    JDBC_c3p0连接池
  • 原文地址:https://www.cnblogs.com/lyraLee/p/12072641.html
Copyright © 2011-2022 走看看