首页 > 其他 > 详细

221、redux实际运用

时间:2020-07-28 22:01:20      阅读:58      评论:0      收藏:0      [点我收藏+]
一、以下总览:
1、状态管理:setstate--新旧值比较-- - render-- - 页面重绘,redux.js单项数据流,react-redux.js状态管理
2、页面初始化时,触发了dispatch--currentReducer--reducer--rootReducer,进而是state由空变为非空,与enhancer无关。
3、状态获取
function createStore(reducer, preloadedState, enhancer) {
  return enhancer(createStore)(reducer, preloadedState);
}
//麻痹的,为了获得最终的状态管理对象,需要经过4轮连锁执行
createStore(
  rootReducer,
  preloadedState,
  compose(functionA,functionB,functionC,functionD)//enhancer
)
//柯里化函数:接受最初函数的第一个参数,用返回值函数接受余下的参数,再返回最终结果的函数。
//柯里化函数:functionA,functionB,functionC,functionD。
function functionA(createStore3) {
  return function createStore4(reducer4, preloadedState4, enhancer4) {//2、实际执行createStore4(reducer, preloadedState),
    var store3=createStore3(reducer3, preloadedState3, enhancer3);//3、其上加工参数,其下加工返回值,最后返回最终结果
    return {
      dispatch: dispatch3,
      subscribe: subscribe3,
      getState: getState3,
      replaceReducer: replaceReducer3
    }
  }
};
function functionB(createStore2) {
  return function createStore3(reducer3, preloadedState3, enhancer3) {
    var store2=createStore2(reducer2, preloadedState2, enhancer2);
    return {
      dispatch: dispatch2,
      subscribe: subscribe2,
      getState: getState2,
      replaceReducer: replaceReducer2
    }
  }
};
function functionC(createStore1) {
  return function createStore2(reducer2, preloadedState2, enhancer2) {
    var store1=createStore1(reducer1, preloadedState1, enhancer1);
    return {
      dispatch: dispatch1,
      subscribe: subscribe1,
      getState: getState1,
      replaceReducer: replaceReducer1
    }
  }
};
function functionD(createStore0) {//1、实际执行functionD(createStore),逐个向上返回
  return function createStore1(reducer1, preloadedState1, enhancer1) {
    var store0=createStore0(reducer0, preloadedState0, enhancer0);
    //4、对返回值store0进行加工,逐个向上返回
    return {
      dispatch: dispatch0,
      subscribe: subscribe0,
      getState: getState0,
      replaceReducer: replaceReducer0
    }
  }
};
(1)compose通过reduce函数引发第1次连锁执行,对functionA、functionB、functionC、functionD进行层层包裹,最后的结果作为enhancer。
(2)createStore把自身作为实参传给enhancer执行,即enhancer(createStore),即functionD(createStore),返回createStore1...,引发第2次连锁执行,最后返回createStore4。
(3)createStore把自身接受到的前两个参数reducer和preloadedState传给createStore4,即createStore4(reducer,preloadedState),进而执行createStore3...,引发第3次连锁执行,最后return时,又引发了第4次连锁执行。
3、compose执行
var arrayFunction = [functionA, functionB, functionC, functionD];
function compose(arrayFunction) {
  return arrayFunction.reduce(function (a, b) {
    return function () {//此处的return的必要性,曾经存疑
      return a(b.apply(undefined, arguments));
    };
  })
}
compose(arrayFunction)(createStore)(reducer, preloadedState);
//第一次循环后的结果如下
function functionOne() {
  return functionA(functionB.apply(undefined, arguments));
}
//第二次循环后的结果如下
function functionTwo() {
  return functionOne(functionC.apply(undefined, arguments));
}
//第三次循环后的结果如下
function functionThree() {
  return functionTwo(functionD.apply(undefined, arguments));
}
//functionThree实际上就是enhancer,通过functionThree(createStore)(reducer, preloadedState)起作用。

二、以下实际应用:
import { createStore, applyMiddleware, compose } from redux;
import thunkMiddleware from redux-thunk;
import rootReducer from reducers/index;
import DevTools from containers/DevTools;
export default function configureStore(preloadedState) {
  const store = createStore(
    rootReducer,
    preloadedState,
    compose(
      applyMiddleware(thunkMiddleware),
      DevTools.instrument()
    )
  )
  return store
}
function createStore(reducer, preloadedState, enhancer) {
  var _ref2;
  if (typeof preloadedState === function && typeof enhancer === undefined) {
    enhancer = preloadedState;
    preloadedState = undefined;
  }
  if (typeof enhancer !== undefined) {
    if (typeof enhancer !== function) {
      throw new Error(Expected the enhancer to be a function.);
    }
    return enhancer(createStore)(reducer, preloadedState);////////////////////////
  }
  if (typeof reducer !== function) {
    throw new Error(Expected the reducer to be a function.);
  }
  var currentReducer = reducer;
  var currentState = preloadedState;
  var currentListeners = [];
  var nextListeners = currentListeners;
  var isDispatching = false;
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice();
    }
  }
  function getState() {
    return currentState;
  }
  function subscribe(listener) {
    if (typeof listener !== function) {
      throw new Error(Expected listener to be a function.);
    }
    var isSubscribed = true;
    ensureCanMutateNextListeners();
    nextListeners.push(listener);
    return function unsubscribe() {
      if (!isSubscribed) {
        return;
      }
      isSubscribed = false;
      ensureCanMutateNextListeners();
      var index = nextListeners.indexOf(listener);
      nextListeners.splice(index, 1);
    };
  }
  function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(Actions must be plain objects.  + Use custom middleware for async actions.);
    }
    if (typeof action.type === undefined) {
      throw new Error(Actions may not have an undefined "type" property.  + Have you misspelled a constant?);
    }
    if (isDispatching) {
      throw new Error(Reducers may not dispatch actions.);
    }
    try {
      isDispatching = true;
      currentState = currentReducer(currentState, action);
    } finally {
      isDispatching = false;
    }
    var listeners = currentListeners = nextListeners;
    for (var i = 0; i < listeners.length; i++) {
      var listener = listeners[i];
      listener();
    }
    return action;
  }
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== function) {
      throw new Error(Expected the nextReducer to be a function.);
    }
    currentReducer = nextReducer;
    dispatch({ type: ActionTypes.INIT });
  }
  function observable() {
    var _ref;
    var outerSubscribe = subscribe;
    return _ref = {
      subscribe: function subscribe(observer) {
        if (typeof observer !== object) {
          throw new TypeError(Expected the observer to be an object.);
        }
        function observeState() {
          if (observer.next) {
            observer.next(getState());
          }
        }
        observeState();
        var unsubscribe = outerSubscribe(observeState);
        return { unsubscribe: unsubscribe };
      }
    }, _ref[result] = function () {
      return this;
    }, _ref;
  }
  dispatch({ type: ActionTypes.INIT });
  return _ref2 = {
    dispatch: dispatch,
    subscribe: subscribe,
    getState: getState,
    replaceReducer: replaceReducer
  }, _ref2[result] = observable, _ref2;
}
function compose() {
  for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
    funcs[_key] = arguments[_key];
  }
  if (funcs.length === 0) {
    return function (arg) {
      return arg;
    };
  }
  if (funcs.length === 1) {
    return funcs[0];
  }
  return funcs.reduce(function (a, b) {
    return function () {
      return a(b.apply(undefined, arguments));
    };
  });
} 
function applyMiddleware() {//这是一个加工dispatch的中间件
  for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
    middlewares[_key] = arguments[_key];
  }
  return function (createStore) {
    return function (reducer, preloadedState, enhancer) {
      var store = createStore(reducer, preloadedState, enhancer);
      var _dispatch = store.dispatch;
      var chain = [];
      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch(action) {//此处为什么不是dispatch:store.dispatch
          return _dispatch(action);
        }
      };
      chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);//return thunkMiddleware(_ref)
      });
      _dispatch = compose.apply(undefined, chain)(store.dispatch);//_dispatch = (function (next){})(store.dispatch) ,这是dispatch的新定义。
      return _extends({}, store, {//store里的dispatch,被这里的dispatch覆盖
        dispatch: _dispatch
      });
    };
  };
}

function combineReducers(reducers) {
  var reducerKeys = Object.keys(reducers);
  var finalReducers = {};
  for (var i = 0; i < reducerKeys.length; i++) {
    var key = reducerKeys[i];
    {
      if (typeof reducers[key] === undefined) {
        warning(No reducer provided for key " + key + ");
      }
    }
    if (typeof reducers[key] === function) {
      finalReducers[key] = reducers[key];
    }
  }
  var finalReducerKeys = Object.keys(finalReducers);
  var unexpectedKeyCache = void 0;
  {
    unexpectedKeyCache = {};
  }
  var shapeAssertionError = void 0;
  try {
    assertReducerShape(finalReducers);
  } catch (e) {
    shapeAssertionError = e;
  }
  return function combination() {
    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var action = arguments[1];
    if (shapeAssertionError) {
      throw shapeAssertionError;
    }
    {
      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
      if (warningMessage) {
        warning(warningMessage);
      }
    }
    var hasChanged = false;
    var nextState = {};
    for (var _i = 0; _i < finalReducerKeys.length; _i++) {
      var _key = finalReducerKeys[_i];
      var reducer = finalReducers[_key];
      var previousStateForKey = state[_key];//previousStateForKey可能为undefined
      var nextStateForKey = reducer(previousStateForKey, action);//可能执行reducer(undefined,action),即执行reducer(defaultState,action)。
      if (typeof nextStateForKey === undefined) {
        var errorMessage = getUndefinedStateErrorMessage(_key, action);
        throw new Error(errorMessage);
      }
      nextState[_key] = nextStateForKey;
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;           
      // const defaultState = {
      //   loading: true,
      // };
      // export default function accountReducer(state = defaultState, action) {
      //   switch (action.type) {
      //     case "register_loading_false":
      //       return {...state, loading: false }
      //       //action匹配成功,state的引用就改变了
      //     default:
      //       return state;
      //       //action匹配不成功,state的引用就不改变了
      //   }
      // }
    }
    //遍历结束,一次性返回结果。
    return hasChanged ? nextState : state;
  };
}

function thunkMiddleware(_ref) {//middleware(middlewareAPI)
  var dispatch = _ref.dispatch;
  var getState = _ref.getState;
  return function (next) {//即return function(store.dispatch);next是dispatch的旧定义,即applyMiddleware函数的chain数组的下一项的执行结果。 
    return function (action) {//返回的函数是dispatch的新定义;其中action是参数,原本只能是对象,经改造后还可以是函数。
      if (typeof action === function) {
        return action(dispatch, getState);//把旧的dispatch、getState传进自定义函数参数里
      }
      return next(action);
    };
  };
}
function componentWillMount() {
  const current = [
    { location: "222", url: "/" },
    { location: "333", url: "/carDetail" },
  ];
  this.props.dispatch(menuChange(current))
}
export const menuChange = function (key) {
  return function (dispatch) {
    dispatch({
      type: "menu_change",
      key
    })
  }
}
function instrument() {
  var monitorReducer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {
    return null;
  };
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  if (typeof options.maxAge === number && options.maxAge < 2) {
    throw new Error(DevTools.instrument({ maxAge }) option, if specified,  + may not be less than 2.);
  }
  return function (createStore) {
    return function (reducer, initialState, enhancer) {
      function liftReducer(r) {
        if (typeof r !== function) {
          if (r && typeof r.default === function) {
            throw new Error(Expected the reducer to be a function.  + Instead got an object with a "default" field.  + Did you pass a module instead of the default export?  + Try passing require(...).default instead.);
          }
          throw new Error(Expected the reducer to be a function.);
        }
        return liftReducerWith(r, initialState, monitorReducer, options);
      }
      var liftedStore = createStore(liftReducer(reducer), enhancer);
      if (liftedStore.liftedStore) {
        throw new Error(DevTools instrumentation should not be applied more than once.  + Check your store configuration.);
      }
      return unliftStore(liftedStore, liftReducer, options);
    };
  };
}

三、附源码
//附:thunk.js
(function webpackUniversalModuleDefinition(root, factory) {
    if (typeof exports === object && typeof module === object)
        module.exports = factory();//common.js模块下执行,factory()的执行结果为null
    else if (typeof define === function && define.amd)
        define([], factory);//require.js异步模块下执行
    else if (typeof exports === object)
        exports["ReduxThunk"] = factory();//ES6模块下执行,factory()的执行结果为null
    else
        root["ReduxThunk"] = factory();//非模块下执行,factory()的执行结果为null
})(
  this, 
  function () {
    return (function (modules) {
      var installedModules = {};
      function __webpack_require__(moduleId) {
        if (installedModules[moduleId])
          return installedModules[moduleId].exports;
        var module = installedModules[moduleId] = {
          exports: {},
          id: moduleId,
          loaded: false        
        };
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        module.loaded = true;
        return module.exports;   
      }
      __webpack_require__.m = modules;
      __webpack_require__.c = installedModules;
      __webpack_require__.p = "";
      return __webpack_require__(0); 
      /* 
      return module.exports = __webpack_require__(1);
      return module.exports = null; 
      即返回结果为一个(空)对象。
      */
      
    })([function (module, exports, __webpack_require__) {
        module.exports = __webpack_require__(1);
      },function (module, exports) {
            use strict;
            exports.__esModule = true;
            exports[default] = thunkMiddleware;//这是最终的注入
            function thunkMiddleware(_ref) {
              var dispatch = _ref.dispatch;
              var getState = _ref.getState;
              return function (next) {// return function (store.dispatch) 
                return function (action) {
                  if (typeof action === function) {
                    return action(dispatch, getState);
                  }
                  return next(action);
                };
              };
            }
        }
      ])
  }
);

//附:instrument.js
use strict;

exports.__esModule = true;
exports.INIT_ACTION = exports.ActionCreators = exports.ActionTypes = undefined;

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

exports.liftAction = liftAction;
exports.liftReducerWith = liftReducerWith;
exports.unliftState = unliftState;
exports.unliftStore = unliftStore;
exports.default = instrument;

var _difference = require(lodash/difference);

var _difference2 = _interopRequireDefault(_difference);

var _union = require(lodash/union);

var _union2 = _interopRequireDefault(_union);

var _isPlainObject = require(lodash/isPlainObject);

var _isPlainObject2 = _interopRequireDefault(_isPlainObject);

var _symbolObservable = require(symbol-observable);

var _symbolObservable2 = _interopRequireDefault(_symbolObservable);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var ActionTypes = exports.ActionTypes = {
  PERFORM_ACTION: PERFORM_ACTION,
  RESET: RESET,
  ROLLBACK: ROLLBACK,
  COMMIT: COMMIT,
  SWEEP: SWEEP,
  TOGGLE_ACTION: TOGGLE_ACTION,
  SET_ACTIONS_ACTIVE: SET_ACTIONS_ACTIVE,
  JUMP_TO_STATE: JUMP_TO_STATE,
  JUMP_TO_ACTION: JUMP_TO_ACTION,
  REORDER_ACTION: REORDER_ACTION,
  IMPORT_STATE: IMPORT_STATE,
  LOCK_CHANGES: LOCK_CHANGES,
  PAUSE_RECORDING: PAUSE_RECORDING
};

var isChrome = (typeof window === undefined ? undefined : _typeof(window)) === object && (typeof window.chrome !== undefined || typeof window.process !== undefined && window.process.type === renderer);

var isChromeOrNode = isChrome || typeof process !== undefined && process.release && process.release.name === node;

/**
 * Action creators to change the History state.
 */
var ActionCreators = exports.ActionCreators = {
  performAction: function performAction(action, trace, traceLimit, toExcludeFromTrace) {
    if (!(0, _isPlainObject2.default)(action)) {
      throw new Error(Actions must be plain objects.  + Use custom middleware for async actions.);
    }

    if (typeof action.type === undefined) {
      throw new Error(Actions may not have an undefined "type" property.  + Have you misspelled a constant?);
    }

    var stack = void 0;
    if (trace) {
      var extraFrames = 0;
      if (typeof trace === function) {
        stack = trace(action);
      } else {
        var error = Error();
        var prevStackTraceLimit = void 0;
        if (Error.captureStackTrace && isChromeOrNode) {
          // avoid error-polyfill
          if (Error.stackTraceLimit < traceLimit) {
            prevStackTraceLimit = Error.stackTraceLimit;
            Error.stackTraceLimit = traceLimit;
          }
          Error.captureStackTrace(error, toExcludeFromTrace);
        } else {
          extraFrames = 3;
        }
        stack = error.stack;
        if (prevStackTraceLimit) Error.stackTraceLimit = prevStackTraceLimit;
        if (extraFrames || typeof Error.stackTraceLimit !== number || Error.stackTraceLimit > traceLimit) {
          var frames = stack.split(\n);
          if (frames.length > traceLimit) {
            stack = frames.slice(0, traceLimit + extraFrames + (frames[0] === Error ? 1 : 0)).join(\n);
          }
        }
      }
    }

    return { type: ActionTypes.PERFORM_ACTION, action: action, timestamp: Date.now(), stack: stack };
  },
  reset: function reset() {
    return { type: ActionTypes.RESET, timestamp: Date.now() };
  },
  rollback: function rollback() {
    return { type: ActionTypes.ROLLBACK, timestamp: Date.now() };
  },
  commit: function commit() {
    return { type: ActionTypes.COMMIT, timestamp: Date.now() };
  },
  sweep: function sweep() {
    return { type: ActionTypes.SWEEP };
  },
  toggleAction: function toggleAction(id) {
    return { type: ActionTypes.TOGGLE_ACTION, id: id };
  },
  setActionsActive: function setActionsActive(start, end) {
    var active = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

    return { type: ActionTypes.SET_ACTIONS_ACTIVE, start: start, end: end, active: active };
  },
  reorderAction: function reorderAction(actionId, beforeActionId) {
    return { type: ActionTypes.REORDER_ACTION, actionId: actionId, beforeActionId: beforeActionId };
  },
  jumpToState: function jumpToState(index) {
    return { type: ActionTypes.JUMP_TO_STATE, index: index };
  },
  jumpToAction: function jumpToAction(actionId) {
    return { type: ActionTypes.JUMP_TO_ACTION, actionId: actionId };
  },
  importState: function importState(nextLiftedState, noRecompute) {
    return { type: ActionTypes.IMPORT_STATE, nextLiftedState: nextLiftedState, noRecompute: noRecompute };
  },
  lockChanges: function lockChanges(status) {
    return { type: ActionTypes.LOCK_CHANGES, status: status };
  },
  pauseRecording: function pauseRecording(status) {
    return { type: ActionTypes.PAUSE_RECORDING, status: status };
  }
};

var INIT_ACTION = exports.INIT_ACTION = { type: @@INIT };

/**
 * Computes the next entry with exceptions catching.
 */
function computeWithTryCatch(reducer, action, state) {
  var nextState = state;
  var nextError = void 0;
  try {
    nextState = reducer(state, action);
  } catch (err) {
    nextError = err.toString();
    if (isChrome) {
      // In Chrome, rethrowing provides better source map support
      setTimeout(function () {
        throw err;
      });
    } else {
      console.error(err);
    }
  }

  return {
    state: nextState,
    error: nextError
  };
}

/**
 * Computes the next entry in the log by applying an action.
 */
function computeNextEntry(reducer, action, state, shouldCatchErrors) {
  if (!shouldCatchErrors) {
    return { state: reducer(state, action) };
  }
  return computeWithTryCatch(reducer, action, state);
}

/**
 * Runs the reducer on invalidated actions to get a fresh computation log.
 */
function recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, shouldCatchErrors) {
  // Optimization: exit early and return the same reference
  // if we know nothing could have changed.
  if (!computedStates || minInvalidatedStateIndex === -1 || minInvalidatedStateIndex >= computedStates.length && computedStates.length === stagedActionIds.length) {
    return computedStates;
  }

  var nextComputedStates = computedStates.slice(0, minInvalidatedStateIndex);
  for (var i = minInvalidatedStateIndex; i < stagedActionIds.length; i++) {
    var actionId = stagedActionIds[i];
    var action = actionsById[actionId].action;

    var previousEntry = nextComputedStates[i - 1];
    var previousState = previousEntry ? previousEntry.state : committedState;

    var shouldSkip = skippedActionIds.indexOf(actionId) > -1;
    var entry = void 0;
    if (shouldSkip) {
      entry = previousEntry;
    } else {
      if (shouldCatchErrors && previousEntry && previousEntry.error) {
        entry = {
          state: previousState,
          error: Interrupted by an error up the chain
        };
      } else {
        entry = computeNextEntry(reducer, action, previousState, shouldCatchErrors);
      }
    }
    nextComputedStates.push(entry);
  }

  return nextComputedStates;
}

/**
 * Lifts an app‘s action into an action on the lifted store.
 */
function liftAction(action, trace, traceLimit, toExcludeFromTrace) {
  return ActionCreators.performAction(action, trace, traceLimit, toExcludeFromTrace);
}

/**
 * Creates a history state reducer from an app‘s reducer.
 */
function liftReducerWith(reducer, initialCommittedState, monitorReducer, options) {
  var initialLiftedState = {
    monitorState: monitorReducer(undefined, {}),
    nextActionId: 1,
    actionsById: { 0: liftAction(INIT_ACTION) },
    stagedActionIds: [0],
    skippedActionIds: [],
    committedState: initialCommittedState,
    currentStateIndex: 0,
    computedStates: [],
    isLocked: options.shouldStartLocked === true,
    isPaused: options.shouldRecordChanges === false
  };

  /**
   * Manages how the history actions modify the history state.
   */
  return function (liftedState, liftedAction) {
    var _ref = liftedState || initialLiftedState,
        monitorState = _ref.monitorState,
        actionsById = _ref.actionsById,
        nextActionId = _ref.nextActionId,
        stagedActionIds = _ref.stagedActionIds,
        skippedActionIds = _ref.skippedActionIds,
        committedState = _ref.committedState,
        currentStateIndex = _ref.currentStateIndex,
        computedStates = _ref.computedStates,
        isLocked = _ref.isLocked,
        isPaused = _ref.isPaused;

    if (!liftedState) {
      // Prevent mutating initialLiftedState
      actionsById = _extends({}, actionsById);
    }

    function commitExcessActions(n) {
      // Auto-commits n-number of excess actions.
      var excess = n;
      var idsToDelete = stagedActionIds.slice(1, excess + 1);

      for (var i = 0; i < idsToDelete.length; i++) {
        if (computedStates[i + 1].error) {
          // Stop if error is found. Commit actions up to error.
          excess = i;
          idsToDelete = stagedActionIds.slice(1, excess + 1);
          break;
        } else {
          delete actionsById[idsToDelete[i]];
        }
      }

      skippedActionIds = skippedActionIds.filter(function (id) {
        return idsToDelete.indexOf(id) === -1;
      });
      stagedActionIds = [0].concat(stagedActionIds.slice(excess + 1));
      committedState = computedStates[excess].state;
      computedStates = computedStates.slice(excess);
      currentStateIndex = currentStateIndex > excess ? currentStateIndex - excess : 0;
    }

    function computePausedAction(shouldInit) {
      var _extends2;

      var computedState = void 0;
      if (shouldInit) {
        computedState = computedStates[currentStateIndex];
        monitorState = monitorReducer(monitorState, liftedAction);
      } else {
        computedState = computeNextEntry(reducer, liftedAction.action, computedStates[currentStateIndex].state, false);
      }
      if (!options.pauseActionType || nextActionId === 1) {
        return {
          monitorState: monitorState,
          actionsById: { 0: liftAction(INIT_ACTION) },
          nextActionId: 1,
          stagedActionIds: [0],
          skippedActionIds: [],
          committedState: computedState.state,
          currentStateIndex: 0,
          computedStates: [computedState],
          isLocked: isLocked,
          isPaused: true
        };
      }
      if (shouldInit) {
        if (currentStateIndex === stagedActionIds.length - 1) {
          currentStateIndex++;
        }
        stagedActionIds = [].concat(stagedActionIds, [nextActionId]);
        nextActionId++;
      }
      return {
        monitorState: monitorState,
        actionsById: _extends({}, actionsById, (_extends2 = {}, _extends2[nextActionId - 1] = liftAction({ type: options.pauseActionType }), _extends2)),
        nextActionId: nextActionId,
        stagedActionIds: stagedActionIds,
        skippedActionIds: skippedActionIds,
        committedState: committedState,
        currentStateIndex: currentStateIndex,
        computedStates: [].concat(computedStates.slice(0, stagedActionIds.length - 1), [computedState]),
        isLocked: isLocked,
        isPaused: true
      };
    }

    // By default, agressively recompute every state whatever happens.
    // This has O(n) performance, so we‘ll override this to a sensible
    // value whenever we feel like we don‘t have to recompute the states.
    var minInvalidatedStateIndex = 0;

    // maxAge number can be changed dynamically
    var maxAge = options.maxAge;
    if (typeof maxAge === function) maxAge = maxAge(liftedAction, liftedState);

    if (/^@@redux\/(INIT|REPLACE)/.test(liftedAction.type)) {
      if (options.shouldHotReload === false) {
        actionsById = { 0: liftAction(INIT_ACTION) };
        nextActionId = 1;
        stagedActionIds = [0];
        skippedActionIds = [];
        committedState = computedStates.length === 0 ? initialCommittedState : computedStates[currentStateIndex].state;
        currentStateIndex = 0;
        computedStates = [];
      }

      // Recompute states on hot reload and init.
      minInvalidatedStateIndex = 0;

      if (maxAge && stagedActionIds.length > maxAge) {
        // States must be recomputed before committing excess.
        computedStates = recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, options.shouldCatchErrors);

        commitExcessActions(stagedActionIds.length - maxAge);

        // Avoid double computation.
        minInvalidatedStateIndex = Infinity;
      }
    } else {
      switch (liftedAction.type) {
        case ActionTypes.PERFORM_ACTION:
          {
            if (isLocked) return liftedState || initialLiftedState;
            if (isPaused) return computePausedAction();

            // Auto-commit as new actions come in.
            if (maxAge && stagedActionIds.length >= maxAge) {
              commitExcessActions(stagedActionIds.length - maxAge + 1);
            }

            if (currentStateIndex === stagedActionIds.length - 1) {
              currentStateIndex++;
            }
            var actionId = nextActionId++;
            // Mutation! This is the hottest path, and we optimize on purpose.
            // It is safe because we set a new key in a cache dictionary.
            actionsById[actionId] = liftedAction;
            stagedActionIds = [].concat(stagedActionIds, [actionId]);
            // Optimization: we know that only the new action needs computing.
            minInvalidatedStateIndex = stagedActionIds.length - 1;
            break;
          }
        case ActionTypes.RESET:
          {
            // Get back to the state the store was created with.
            actionsById = { 0: liftAction(INIT_ACTION) };
            nextActionId = 1;
            stagedActionIds = [0];
            skippedActionIds = [];
            committedState = initialCommittedState;
            currentStateIndex = 0;
            computedStates = [];
            break;
          }
        case ActionTypes.COMMIT:
          {
            // Consider the last committed state the new starting point.
            // Squash any staged actions into a single committed state.
            actionsById = { 0: liftAction(INIT_ACTION) };
            nextActionId = 1;
            stagedActionIds = [0];
            skippedActionIds = [];
            committedState = computedStates[currentStateIndex].state;
            currentStateIndex = 0;
            computedStates = [];
            break;
          }
        case ActionTypes.ROLLBACK:
          {
            // Forget about any staged actions.
            // Start again from the last committed state.
            actionsById = { 0: liftAction(INIT_ACTION) };
            nextActionId = 1;
            stagedActionIds = [0];
            skippedActionIds = [];
            currentStateIndex = 0;
            computedStates = [];
            break;
          }
        case ActionTypes.TOGGLE_ACTION:
          {
            // Toggle whether an action with given ID is skipped.
            // Being skipped means it is a no-op during the computation.
            var _actionId = liftedAction.id;

            var index = skippedActionIds.indexOf(_actionId);
            if (index === -1) {
              skippedActionIds = [_actionId].concat(skippedActionIds);
            } else {
              skippedActionIds = skippedActionIds.filter(function (id) {
                return id !== _actionId;
              });
            }
            // Optimization: we know history before this action hasn‘t changed
            minInvalidatedStateIndex = stagedActionIds.indexOf(_actionId);
            break;
          }
        case ActionTypes.SET_ACTIONS_ACTIVE:
          {
            // Toggle whether an action with given ID is skipped.
            // Being skipped means it is a no-op during the computation.
            var start = liftedAction.start,
                end = liftedAction.end,
                active = liftedAction.active;

            var actionIds = [];
            for (var i = start; i < end; i++) {
              actionIds.push(i);
            }if (active) {
              skippedActionIds = (0, _difference2.default)(skippedActionIds, actionIds);
            } else {
              skippedActionIds = (0, _union2.default)(skippedActionIds, actionIds);
            }

            // Optimization: we know history before this action hasn‘t changed
            minInvalidatedStateIndex = stagedActionIds.indexOf(start);
            break;
          }
        case ActionTypes.JUMP_TO_STATE:
          {
            // Without recomputing anything, move the pointer that tell us
            // which state is considered the current one. Useful for sliders.
            currentStateIndex = liftedAction.index;
            // Optimization: we know the history has not changed.
            minInvalidatedStateIndex = Infinity;
            break;
          }
        case ActionTypes.JUMP_TO_ACTION:
          {
            // Jumps to a corresponding state to a specific action.
            // Useful when filtering actions.
            var _index = stagedActionIds.indexOf(liftedAction.actionId);
            if (_index !== -1) currentStateIndex = _index;
            minInvalidatedStateIndex = Infinity;
            break;
          }
        case ActionTypes.SWEEP:
          {
            // Forget any actions that are currently being skipped.
            stagedActionIds = (0, _difference2.default)(stagedActionIds, skippedActionIds);
            skippedActionIds = [];
            currentStateIndex = Math.min(currentStateIndex, stagedActionIds.length - 1);
            break;
          }
        case ActionTypes.REORDER_ACTION:
          {
            // Recompute actions in a new order.
            var _actionId2 = liftedAction.actionId;
            var idx = stagedActionIds.indexOf(_actionId2);
            // do nothing in case the action is already removed or trying to move the first action
            if (idx < 1) break;
            var beforeActionId = liftedAction.beforeActionId;
            var newIdx = stagedActionIds.indexOf(beforeActionId);
            if (newIdx < 1) {
              // move to the beginning or to the end
              var count = stagedActionIds.length;
              newIdx = beforeActionId > stagedActionIds[count - 1] ? count : 1;
            }
            var diff = idx - newIdx;

            if (diff > 0) {
              // move left
              stagedActionIds = [].concat(stagedActionIds.slice(0, newIdx), [_actionId2], stagedActionIds.slice(newIdx, idx), stagedActionIds.slice(idx + 1));
              minInvalidatedStateIndex = newIdx;
            } else if (diff < 0) {
              // move right
              stagedActionIds = [].concat(stagedActionIds.slice(0, idx), stagedActionIds.slice(idx + 1, newIdx), [_actionId2], stagedActionIds.slice(newIdx));
              minInvalidatedStateIndex = idx;
            }
            break;
          }
        case ActionTypes.IMPORT_STATE:
          {
            if (Array.isArray(liftedAction.nextLiftedState)) {
              // recompute array of actions
              actionsById = { 0: liftAction(INIT_ACTION) };
              nextActionId = 1;
              stagedActionIds = [0];
              skippedActionIds = [];
              currentStateIndex = liftedAction.nextLiftedState.length;
              computedStates = [];
              committedState = liftedAction.preloadedState;
              minInvalidatedStateIndex = 0;
              // iterate through actions
              liftedAction.nextLiftedState.forEach(function (action) {
                actionsById[nextActionId] = liftAction(action, options.trace || options.shouldIncludeCallstack);
                stagedActionIds.push(nextActionId);
                nextActionId++;
              });
            } else {
              var _liftedAction$nextLif = liftedAction.nextLiftedState;
              // Completely replace everything.

              monitorState = _liftedAction$nextLif.monitorState;
              actionsById = _liftedAction$nextLif.actionsById;
              nextActionId = _liftedAction$nextLif.nextActionId;
              stagedActionIds = _liftedAction$nextLif.stagedActionIds;
              skippedActionIds = _liftedAction$nextLif.skippedActionIds;
              committedState = _liftedAction$nextLif.committedState;
              currentStateIndex = _liftedAction$nextLif.currentStateIndex;
              computedStates = _liftedAction$nextLif.computedStates;


              if (liftedAction.noRecompute) {
                minInvalidatedStateIndex = Infinity;
              }
            }

            break;
          }
        case ActionTypes.LOCK_CHANGES:
          {
            isLocked = liftedAction.status;
            minInvalidatedStateIndex = Infinity;
            break;
          }
        case ActionTypes.PAUSE_RECORDING:
          {
            isPaused = liftedAction.status;
            if (isPaused) {
              return computePausedAction(true);
            }
            // Commit when unpausing
            actionsById = { 0: liftAction(INIT_ACTION) };
            nextActionId = 1;
            stagedActionIds = [0];
            skippedActionIds = [];
            committedState = computedStates[currentStateIndex].state;
            currentStateIndex = 0;
            computedStates = [];
            break;
          }
        default:
          {
            // If the action is not recognized, it‘s a monitor action.
            // Optimization: a monitor action can‘t change history.
            minInvalidatedStateIndex = Infinity;
            break;
          }
      }
    }

    computedStates = recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, options.shouldCatchErrors);
    monitorState = monitorReducer(monitorState, liftedAction);
    return {
      monitorState: monitorState,
      actionsById: actionsById,
      nextActionId: nextActionId,
      stagedActionIds: stagedActionIds,
      skippedActionIds: skippedActionIds,
      committedState: committedState,
      currentStateIndex: currentStateIndex,
      computedStates: computedStates,
      isLocked: isLocked,
      isPaused: isPaused
    };
  };
}

/**
 * Provides an app‘s view into the state of the lifted store.
 */
function unliftState(liftedState) {
  var computedStates = liftedState.computedStates,
      currentStateIndex = liftedState.currentStateIndex;
  var state = computedStates[currentStateIndex].state;

  return state;
}

/**
 * Provides an app‘s view into the lifted store.
 */
function unliftStore(liftedStore, liftReducer, options) {
  var _extends3;

  var lastDefinedState = void 0;
  var trace = options.trace || options.shouldIncludeCallstack;
  var traceLimit = options.traceLimit || 10;

  function getState() {
    var state = unliftState(liftedStore.getState());
    if (state !== undefined) {
      lastDefinedState = state;
    }
    return lastDefinedState;
  }

  function dispatch(action) {
    liftedStore.dispatch(liftAction(action, trace, traceLimit, dispatch));
    return action;
  }

  return _extends({}, liftedStore, (_extends3 = {

    liftedStore: liftedStore,

    dispatch: dispatch,

    getState: getState,

    replaceReducer: function replaceReducer(nextReducer) {
      liftedStore.replaceReducer(liftReducer(nextReducer));
    }
  }, _extends3[_symbolObservable2.default] = function () {
    return _extends({}, liftedStore[_symbolObservable2.default](), {
      subscribe: function subscribe(observer) {
        if ((typeof observer === undefined ? undefined : _typeof(observer)) !== object) {
          throw new TypeError(Expected the observer to be an object.);
        }

        function observeState() {
          if (observer.next) {
            observer.next(getState());
          }
        }

        observeState();
        var unsubscribe = liftedStore.subscribe(observeState);
        return { unsubscribe: unsubscribe };
      }
    });
  }, _extends3));
}

/**
 * Redux instrumentation store enhancer.
 */
function instrument() {
  var monitorReducer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {
    return null;
  };
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  if (typeof options.maxAge === number && options.maxAge < 2) {
    throw new Error(DevTools.instrument({ maxAge }) option, if specified,  + may not be less than 2.);
  }

  return function (createStore) {
    return function (reducer, initialState, enhancer) {

      function liftReducer(r) {
        if (typeof r !== function) {
          if (r && typeof r.default === function) {
            throw new Error(Expected the reducer to be a function.  + Instead got an object with a "default" field.  + Did you pass a module instead of the default export?  + Try passing require(...).default instead.);
          }
          throw new Error(Expected the reducer to be a function.);
        }
        return liftReducerWith(r, initialState, monitorReducer, options);
      }

      var liftedStore = createStore(liftReducer(reducer), enhancer);
      if (liftedStore.liftedStore) {
        throw new Error(DevTools instrumentation should not be applied more than once.  + Check your store configuration.);
      }

      return unliftStore(liftedStore, liftReducer, options);
    };
  };
}

 

221、redux实际运用

原文:https://www.cnblogs.com/gushixianqiancheng/p/13392540.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!