redux之createStore

678 阅读5分钟

cretaeStore

此函数是用来创建一个单应用存放所有state的store的函数。它接收三个参数。并且返回dispatch, subscribe, getSatte, replaceRecuder, observable。

参数

  • reducer
  1. 接收两个参数(state,action),并且返回新的state树。
  2. 通常会使用combineReducers将自己定义的reducers进行组合。并返回一个函数。

随着应用变得复杂,需要对reducer函数进行拆分, 拆分后的每一块独立负责管理state的一部分。

combineReducers辅助函数的作用是,把一个有多个不同的reducer函数作为value的object,合并成一个最终的reducer函数(返回的函数对旧的state和新的state做了浅比较!==, 如果浅比较不相等, 则返回新的state,否则就是旧的state,为的是性能优化)。然后把这个函数传递给createStore。下边源码的最下边

function combineReducers(reducers) {  var reducerKeys = Object.keys(reducers);  var finalReducers = {};  for (var i = 0; i < reducerKeys.length; i++) {    var key = reducerKeys[i];    if (process.env.NODE_ENV !== 'production') {      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); // This is used to make sure we don't warn about the same  // keys multiple times.  var unexpectedKeyCache;  if (process.env.NODE_ENV !== 'production') {    unexpectedKeyCache = {};  }  var shapeAssertionError;  try {    assertReducerShape(finalReducers);  } catch (e) {    shapeAssertionError = e;  }  return function combination(state, action) {    if (state === void 0) {      state = {};    }    if (shapeAssertionError) {      throw shapeAssertionError;    }    if (process.env.NODE_ENV !== 'production') {      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];      var nextStateForKey = reducer(previousStateForKey, action);      if (typeof nextStateForKey === 'undefined') {        var errorMessage = getUndefinedStateErrorMessage(_key, action);        throw new Error(errorMessage);      }      nextState[_key] = nextStateForKey;      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;    }    hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;    return hasChanged ? nextState : state;  };}

当然也可以使用其它类似的函数来管理所有的reducers。

  • preloadedState

state树的初始化数据。他和reducer参数中的es6的默认值。二选其一。

初始值的作用,是为了不让reducer返回state=undefiend,是为了避免错误扩散。

场景: 1.不使用combineReducers时,

1.1 只要使用preloadedState时, createStore都会取preloadedState当做初始值。假如在reducer中使用默认值, reducer的默认值优先级则小与preloadedState;

1.2.不使用preloadedState时, 使用reducer默认值,则会redcer的优先级高于preloadedState。

场景一。看例子1.

  //例子1.不使用combineReducers的时候。使用preloadedState和不使用默认值的优先级。

let preloadedState= {OneReducer :{a:1}}    
store = createStore(OneReducer, preloadedState)        
store.subscribe(()=>{    
    console.log( "不使用combineReducers的时候。preloadedState和默认值的优先级",  store.getState())   
})

//reducer
//场景一,且使用preloadedState时export  function OneReducer  (state, action)  {  let newState = {}  switch (action.type) {    case 'one_type': {      newState ={...state, ...action.params.data}    }    break;    default:newState = state;  }  return newState || state}

会发现,当使用preloadedState且不使用es6的默认值时, 会自动取preloadedState放到state树上。

下边是createStore部分源码,只截取dispatch和preloadedState部分。

function createStore(reducer, preloadedState, enhancer) {  var _ref2;  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {    enhancer = preloadedState;    preloadedState = undefined;  }  var currentReducer = reducer;  var currentState = preloadedState;  var currentListeners = [];  var nextListeners = currentListeners;  var isDispatching = false;  function getState() {    if (isDispatching) {      throw new Error('You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.');    }    return currentState;  }   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;  }   dispatch({    type: ActionTypes.INIT  });  return _ref2 = {    dispatch: dispatch,    subscribe: subscribe,    getState: getState,    replaceReducer: replaceReducer  }, _ref2[$$observable] = observable, _ref2;}

    在上边源码中,可看到createStore内部自调用了dispatch并且给定了默认的action、在dispatch函数中, 会调用每一个reducer函数。并且赋给reducer函数参数为currentState,action。因为是dispatch(redux默认的action)所以此时的currentState则是 preloadedState参数的值。所以reducers函数返回的state树,也就是preloadedState值。

     由于在调用createStore时, 会默认初始化调用dispatch, 在dispatch中, 会循环调用每一个reducer。此时如果preloadedState和es6默认值都不存在的话, 会使state为undefined并且返回。如果返回了state=undefined,那在具体使用时,会因为找不到而报错。所以redux干脆就不让state=undefined。会加层校验。

场景二。看例子2.

//例子2.不使用combineReducers的时候。不使用preloadedState且使用默认值的优先级。

store = createStore(OneReducer)        
store.subscribe(()=>{    
    console.log( "不使用combineReducers的时候。preloadedState和默认值的优先级",  store.getState())   
})

//reducer
//场景二,
let initdata = {  OneReducer:{value:"哈哈哈哈,我是state的默认值"}}
export  function OneReducer  (state = initdata, action)  {  
    let newState = {}  
    switch (action.type) {    
        case 'one_type': {      
            newState ={...state, ...action.params.data}    
        }    
        break;    
        default:newState = state;  
    }  
    return newState || state
}

当不使用preoloadedState时, 因为使用了es6的默认值功能。所以在初始dispatch时,调用reducer参数state=undefined,也不会报错。

场景三。使用combineReducers,使用preloadedState,且不使用es6默认值时。

//reducers
import {combineReducers} from "redux";import OneReducer from "./one.reducer.js";import TwoReducer from "./two.reducer.js";import ThreeReducer from "./three.reducer.js";export default  combineReducers({    OneReducer,    TwoReducer,    ThreeReducer})

//store
 let preloadedState={OneReducer :{OneReducer:1}}    store = createStore(Reducers, preloadedState)//Reducers就是上边定义的类组件        store.subscribe(()=>{      console.log( "使用combineReducers的时候。preloadedState和默认值的优先级", store.getState())    })//onereducer
export  function OneReducer  (state , action)  {  
    let newState = {}  
    switch (action.type) {    
        case 'one_type': {      
            newState ={...state, ...action.params.data}    
        }    
        break;    
        default:newState = state;  
    }  
    return newState || state
}//combineReducers中的一个调用方法,源码
function assertReducerShape(reducers) {  Object.keys(reducers).forEach(function (key) {    var reducer = reducers[key];    var initialState = reducer(undefined, {//这里显示的传递undefined      type: ActionTypes.INIT    });    if (typeof initialState === 'undefined') {      throw new Error("Reducer \"" + key + "\" returned undefined during initialization. " + "If the state passed to the reducer is undefined, you must " + "explicitly return the initial state. The initial state may " + "not be undefined. If you don't want to set a value for this reducer, " + "you can use null instead of undefined.");    }    if (typeof reducer(undefined, {      type: ActionTypes.PROBE_UNKNOWN_ACTION()    }) === 'undefined') {      throw new Error("Reducer \"" + key + "\" returned undefined when probed with a random type. " + ("Don't try to handle " + ActionTypes.INIT + " or other actions in \"redux/*\" ") + "namespace. They are considered private. Instead, you must return the " + "current state for any unknown actions, unless it is undefined, " + "in which case you must return the initial state, regardless of the " + "action type. The initial state may not be undefined, but can be null.");    }  });}

由于使用了combineReducers,所以会先调用combineReducers函数。preloadedState不会再此函数中出现。只能取默认值。在combineReducers中, 会默认调用一次每一个reducer,并且state赋值为undefined。此时在reducer中的默认值,就会起作用**。**

此时还没有使用默认值, 所以redux内部会报异常如下

场景四。使用combineReducers,使用preloadedState,且使用es6默认值时。

//store
 let preloadedState={OneReducer :{one:1}}    store = createStore(Reducers, preloadedState)//Reducers就是上边定义的类组件        store.subscribe(()=>{      console.log( "使用combineReducers的时候。preloadedState和默认值的优先级", store.getState())    })//onereducer
let initdata = {  OneReducer:{value:"哈哈哈哈,我是state的默认值"}}export  function OneReducer  (state = initdata , action)  {  
    let newState = {}  
    switch (action.type) {    
        case 'one_type': {      
            newState ={...state, ...action.params.data}    
        }    
        break;    
        default:newState = state;  
    }  
    return newState || state
}

会发现,其实默认值会采用preloadedState的。

其实无论那种场景, 只要使用的preloadedState,都会以这个值为主。

场景五。使用combineReducers,不使用preloadedState,且使用es6默认值时。

//store

store = createStore(Reducers)//Reducers就是上边定义的类组件        
store.subscribe(()=>{      
    console.log( "使用combineReducers的时候。preloadedState和默认值的优先级", store.getState())    
})

//onereducer
let initdata = {  one:"哈哈哈哈,我是state的默认值"}export  function OneReducer  (state = initdata , action)  {  
    let newState = {}  
    switch (action.type) {    
        case 'one_type': {      
            newState ={...state, ...action.params.data}    
        }    
        break;    
        default:newState = state;  
    }  
    return newState || state
}

  • enhancer

它是一个组合store creator的高阶函数, 返回一个新的强化过的store 。

可以指定使用第三方插件,redux附带的唯一存储增强器是applyMiddleware

import {createStore, applyMiddleware} from "redux";
store = createStore(Reducers, preloadedState, applyMiddleware())

//enhancer参数的源码中使用如下
 return enhancer(createStore)(reducer, preloadedState);其实就相当于
return applyMiddleware()(createStore)(reducer, preloadedState);




//applyMiddleware源码

function applyMiddleware() {  for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) {    middlewares[_key] = arguments[_key];  }  return function (createStore) {    return function () {      var store = createStore.apply(void 0, arguments);      var _dispatch = function dispatch() {        throw new Error("Dispatching while constructing your middleware is not allowed. " + "Other middleware would not be applied to this dispatch.");      };      var middlewareAPI = {        getState: store.getState,        dispatch: function dispatch() {          return _dispatch.apply(void 0, arguments);        }      };      var chain = middlewares.map(function (middleware) {        return middleware(middlewareAPI);      });      _dispatch = compose.apply(void 0, chain)(store.dispatch);      return _objectSpread({}, store, {        dispatch: _dispatch      });    };  };}

上边源码中表示:applyMiddleware返回一个函数,返回的函数里,又返回了一个函数。运用的是函数式编程的柯理化编程(将多个参数的函数转换成接收一个参数的函数。)

return applyMiddleware()(createStore)(reducer, preloadedState);时,

首先会先调用applyMiddleware(),返回第一个接收createStore的函数。

applyMiddleware()(createStore),返回一个增强store的函数。

applyMiddleware()(createStore)(reducer, preloadedState),返回的就是增强后的store。

在最后的返回函数中, 我们可以看到,

1. 先是创建了store, 然后将声明了一个_dispatch函数。

2. 继续声明了middlewareAPI, 并附初始化值, store.getState, 和自定义的_dispatch函数。

3. 将传进来的中间件遍历附上middlewareAPI,返回数组。

4.将所有的中间件组合强化的dispatch赋值给_dispatch。

5.最终返回store。

学艺不精,请多多指教。