ReactWeb前端之路Web 前端开发

mini-redux系列之一:createStore

2018-05-12  本文已影响6人  2f1b6dfcc208

  最近一周看了redux、react-redux的源码,觉得又收获了很多,对于redux不再是停留在应用层面,而是深入底层原理,了解了整个库的设计思路。在读源码的过程中,虽然仍有小部分内容感到晦涩,但是不影响对整个库的理解,同时,自己根据个人理解参照官方库自定义实现了一个简化版的mini-redux、mini-react-redux,去除了官方库的一些额外判断以及错误处理。经测试,在已实现的功能上完全可以替代官方库正确运行。注:本项目仅供学习参考使用,完整源码在 github
  本系列文章是对mini-redux、mini-react-redux的一些源码分析,该文章为第一篇,主要介绍createStore函数的实现。
目录结构如下:

image.png
首先介绍一下mini-redux的入口文件index.js
import createStore from './createStore';
import bindActionCreators from './bindActionCreators';
import applyMiddleware from './applyMiddleware';
import compose from './compose';
import combineReducers from './combineReducers'

export { createStore, bindActionCreators, applyMiddleware, compose, combineReducers };

redux最核心的概念便是store,下面是createStore的精简版实现,具体分析都有注释

/* createStore.js */

//  因为第二个参数和第三个参数可选,所以需要做一些前置判断
export default function createStore(reducer, preloadedState, enhancer) {
  // 如果reducer不是函数类型,报错
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.');
  }

  // 如果第二个参数类型为function,则需要判断是否传入了第三个参数
  if (typeof preloadedState === 'function') {
    if (typeof enhancer !== 'undefined') {
      // 如果传入了第三个参数,则报错,因为此处第二个参数preloadedState被认为是函数类型,不合理
      throw new Error('Expected the preloadedState not to be a function.');
    }

    // 如果只传入了两个值且第二个参数类型为function,则将第二个参数的值赋给enhancer,preloadedState置为undefined
    enhancer = preloadedState;
    preloadedState = undefined;
  }

  // 如果enhancer非空,判断是否为函数类型
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.');
    }

    // 如果enhancer存在且类型正确,则执行enhancer并返回结果作为store。具体实现需要配合后面的applyMiddleware进行理解
    return enhancer(createStore)(reducer, preloadedState);
  }

  // 声明单一的state tree、监听器数组
  let currentState = preloadedState;
  const currentListeners = [];
  
  // 获取状态树
  function getState() {
    return currentState;
  }
  
  // 订阅事件
  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.');
    }
    currentListeners.push(listener);

    // 这里应当返回一个函数,当它执行时取消该listener的监听
    return function unsubscribe() {
      const index = currentListeners.indexOf(listener);
      currentListeners.splice(index, 1);
    };
  }
  
  // dispatch的实现
  function dispatch(action) {
    if (typeof action !== 'object') {
      throw new Error('Actions must be plain objects.');
    }
    if (typeof action.type === 'undefined') {
      throw new Error('Actions may not have an undefined "type" property.');
    }
    
    // 根据reducer执行的结果更新状态树
    currentState = reducer(currentState, action);
    // 遍历监听器数组,执行每个listener函数
    currentListeners.forEach(listener => listener());

    return action;
  }

  // 生成store时,会默认派发一个初始化的action,用来初始化状态树。注意:这里的type不能与其它重名
  dispatch({ type: '@@redux/INIT' });
  
  // 返回一个具有getState、subscribe、dispatch方法的对象,即store
  return {
    getState,
    subscribe,
    dispatch
  };
}

相关文章

mini-redux系列之一:createStore
mini-redux系列之二:applyMiddleware
mini-redux系列之三:combineReducers
mini-redux系列之四:bindActionCreators
mini-react-redux系列之一:Provider
mini-react-redux系列之二:connect
redux-thunk以及自定义redux中间件

上一篇下一篇

猜你喜欢

热点阅读