手写精简版的 Redux 状态容器

1.Redux的简单使用

如果下面的代码看不懂,可以看前面的 Redux简单入门 这篇博客。


/*==================action=====================*/
var add=(number)=>{
    return{
        type:'add',
        number:number,
    }
}

/*==================reducer=====================*/
var reducer=(state,action)=>{
    var {number,type}=action;
    switch (type){
        case 'add':
            return Object.assign({},state,{num:state.num+number,});
        default:
            return state;
    }
}

/*==================store=====================*/
var redux=require('redux');
var initValue={
    num:0,
}
var store =redux.createStore(reducer,initValue);

/*==================简单使用====================*/
console.log('初始化的状态树:',store.getState()); // 0
/*1.分发一个 add 事件*/
store.dispatch(add(10) );
console.log('+10后的状态树:',store.getState()); //10

上面的代码主要使用了redux中的createStore模块。通过调用createStore(reducer,initValue)来创建一个store对象。那么接下来我们看一下createStore(reducer,initValue)函数的源码:

2.查看创建store对象的源码

/*
    这个createStore函数返回了store对象。
    暴露了四个接口:dispatch,subscribe,getState,replaceReducer
    参数一:reducer ; 参数二:初始化状态树 ; 参数三:store的增强器
*/
;function createStore(reducer, preloadedState, enhancer) {
  //...

  var currentReducer = reducer;/*将传递进来的redcer赋值给currentReducer*/
  var currentState = preloadedState;/*将传进来初始化的状态树赋值给currentState*/
  var currentListeners = [];/*定义一个数组存放监听的回调函数*/

  //...

  /*返回当前的状态树*/
  function getState() {
    return currentState;
  }

  /*
        添加监听的函数( 订阅 ) ;
        返回一个可以移除监听的函数
   */
  function subscribe(listener) {
    //...

    nextListeners.push(listener);/* 把订阅的函数添加到nextListeners数组中 */

    /* 返回一个可以移除监听的函数:listener */
    return function unsubscribe() {
      //...

      var index = nextListeners.indexOf(listener);
      nextListeners.splice(index, 1);
    };
  }

  /*分发action的函数,返回结果也是该action*/
  function dispatch(action) {
    //...

    try {
      //...
       /*
        调用reducer函数,并把 当前的状态树和action 传递过去
        返回当前新的状态树,来更新状态树。
        */
      currentState = currentReducer(currentState, action);
    } finally {
      //...
    }

    /*更新完状态树后,使用for循环调用所有监听的函数*/
    var listeners = currentListeners = nextListeners;
    for (var i = 0; i < listeners.length; i++) {
      var listener = listeners[i];
      listener();
    }

    return action;
  }

  /*替换reducer, 从新初始化状态树*/
  function replaceReducer(nextReducer) {
    //...

    currentReducer = nextReducer;
    dispatch({ type: ActionTypes.INIT });
  }


  // 初始化 store 里的 state tree( 默认初始化时自动分发一个action )
  dispatch({ type: ActionTypes.INIT });

  //返回 store 暴漏出的接口
  return _ref2 = {
    dispatch: dispatch,
    subscribe: subscribe,
    getState: getState,
    replaceReducer: replaceReducer
  }
}

3.手写一个MiniRedux

1.编写MiniRedux的结构

新建一个MiniRedux.js文件,编写下面代码:

/**
 * 创建store对象的函数: createStore
 * @param reducer
 * @param initState 初始化状态树
 * @returns {{dispatch: dispatch, subscribe: subscribe, getState: getState}}
 */
function createStore(reducer,initState) {

    var currentReducer = reducer;/*接收传递进来的reducer函数*/
    var currentState = initState;/**默认初始化状态树*/
    var currentListeners = [];/**所有的监听函数*/

    /**
     * 分发action函数
     */
    function dispatch(action) {
        return action;
    }

    /**
     * 添加订阅事件
     */
    function subscribe(listener) {

    }

    /***
     * 获取当前的状态树
     * @returns {*}
     */
    function getState() {
        return currentState;
    }

    /**
     * 最终暴露的接口 API
     */
    return{
        dispatch: dispatch,
        subscribe: subscribe,
        getState: getState,
    }
}
/*ES5 声明函数导出*/
module.exports=createStore;

2.编写一个test.js测试文件

/*==================action=====================*/
var add=(number)=>{
    return{
        type:'add',
        number:number,
    }
}
/*==================reducer=====================*/
var reducer=(state,action)=>{
    var {number,type}=action;
    switch (type){
        case 'add':
            return Object.assign({},state,{num:state.num+number,});
        default:
            return state;
    }
}
/*==================store=====================*/
/*这里ES5导入自己编写的MiniRedux框架*/
var createStore = require('./MiniRedux');
var initState={
    num:0
}
var store = createStore(reducer,initState);
/*1.打印初始化的状态树*/
console.log('初始化的状态树:',store.getState());

控制台打印输出:

初始化的状态树: { num: 0 }

3.编写分发事件的逻辑

  /**
     * 分发action函数
     */
    function dispatch(action) {

        if (typeof action.type === 'undefined') {
            throw new Error('action 对象必须包含 type属性 ');
        }

        /**调用传递进来的reducer函数, reducer是一个纯函数。返回新的状态树*/
        currentState = currentReducer(currentState, action);

        return action;
    }

添加测试代码:

// ...
var createStore = require('./MiniRedux');
var initState={
    num:0
}
var store = createStore(reducer,initState);
/*1.打印初始化的状态树*/
console.log('初始化的状态树:',store.getState());

/*2.分发一个action事件*/
store.dispatch( add(100) );
console.log('+100后的状态树:',store.getState()); //100

控制台输出:

初始化的状态树: { num: 0 }
+100后的状态树: { num: 100 }

4.添加订阅事件

/**
 * 创建store对象的函数
 * @param reducer
 * @param initState 初始化状态树
 * @returns {{dispatch: dispatch, subscribe: subscribe, getState: getState}}
 */
function createStore(reducer,initState) {

    var currentReducer = reducer;
    var currentState = initState;
    var currentListeners = [];

    /**
     * 分发action函数
     */
    function dispatch(action) {

        if (typeof action.type === 'undefined') {
            throw new Error('action 对象必须包含 type属性 ');
        }

        /**调用传递进来的reducer函数, reducer是一个纯函数。返回新的状态树*/
        currentState = currentReducer(currentState, action);


        var listeners = currentListeners;

        /**更新状态树之后,马上遍历订阅事件的数组,并调用每一个订阅事件*/
        for (var i = 0; i < listeners.length; i++) {
            var listener = listeners[i];
            /**调用每一个订阅事件*/
            listener();
        }
        return action;
    }

    /**
     * 添加订阅事件
     * @param listener 订阅事件
     * @returns {unSubScribe}  取消订阅事件
     */
    function subscribe(listener) {

        if (typeof listener !== 'function') {
            throw new Error('listener 不是一个函数');
        }

        /**把订阅事件添加多数组中去*/
        currentListeners.push(listener);

        /**
         * 返回一个取消订阅的函数
         */
        return function unSubScribe() {
            /**找到要取消的订阅的函数*/
            var index = currentListeners.indexOf(listener);
            /**从数组中移出要订阅的函数*/
            currentListeners.splice(index, 1);
        }

    }

    /***
     * 获取当前的状态树
     * @returns {*}
     */
    function getState() {
        return currentState;
    }

    /**
     * 最终暴露的接口 API
     */
    return{
        dispatch: dispatch,
        subscribe: subscribe,
        getState: getState,
    }
}
/*ES5 声明函数导出*/
module.exports=createStore;

编写测试代码:

//...

/*==================store=====================*/
var createStore = require('./MiniRedux');
var initState={
    num:0
}
var store = createStore(reducer,initState);

/*添加给订阅事件*/
var onChange=function () {
    console.log('更新后的状态树:',store.getState());
}
var unSubscribe=store.subscribe(onChange);


/*1.打印初始化的状态树*/
console.log('初始化的状态树:',store.getState());

/*2.分发action事件*/
store.dispatch( add(100) );

store.dispatch( add(100) );
/**取消监听事件*/
unSubscribe(onChange)
store.dispatch( add(100) );

控制台打印输出:

初始化的状态树: { num: 0 }
更新后的状态树: { num: 100 }
更新后的状态树: { num: 200 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值