[源码阅读]redux源码阅读

793 阅读4分钟
  • 11.3 完成redux主流程的源码阅读
  • 11.4 完成redux中间件相关源码
  • 11.5 了解一下ES,CQRS,Flux相关知识

前言:

准备:

源码:

git clone https://github.com/lxchuan12/redux-analysis.git
cd redux-analysi/redux
npm i
npm run build

好吧,实不相瞒,这样我报错了,具体为啥,尚未查明,毕竟我一直都有很多奇奇怪怪的问题😒,so,‘机智’的summer,直接看若川大佬的examples文件夹里面的内容,也不会影响使用。

redux

好久没看redux了,先浅浅的复习一下吧

redux是什么?

Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。

视图与状态一一对应,所有的状态保存在一个对象里面

redux图.png

  • 首先用户通过View发出Action
    • 但是,你view发出一次消息就需要一个Action,我们会定义一个函数来生成Action,这个函数就叫做Action Creators
  • 发出Action就要使用dispatch,大概就是告诉store告诉你想干嘛
  • 然后Store调用Reducer
    • Reducer是一个函数,他接受两个参数
      • PreState
      • Action
    • 他会返回一个新的StateStore
    • 至于为啥会有很多reducer,因为他们将reducer进行拆分了拆分 Reducer 逻辑 | Redux 中文官网
  • Store会将这个新的Stateview
  • State一旦发生变化,那么我们store就会监听subscribe,然后更新view

这里放一张官网的图,我感觉其实还是很清晰的。

redux工作.gif

redux的特点

  • 单向数据流
  • UI和数据逻辑分开

步入正题:

文件目录.png

index.js

index.js是入口文件,其实就是提供了reudx的方法

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

createStore.js

主要就是用于Store的生成

store身上有几个函数

  • dispatch:将subscribe收集到的函数依次执行
  • subscribe:订阅收集函数,将他们存放在数组中,等到触发dispatch依次执行,返回一个unsubscribe函数,取消订阅,取消监听
  • replaceReducer: 主要用于redux开发者工具,对比当前和上一次操作的异同
  • getState:就是获取当前的state
return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }

首先先来看最简单的两个

getState()

获取当前的state

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
  }

replaceReducer()

替换当前reducer,并重新初始化state

  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }

subscribe()

注册监听事件,然后返回取消的函数,将所有的订阅函数都用一个数组来存放

function subscribe(listener) {
    let isSubscribed = true
    ensureCanMutateNextListeners()
    //将当前的这个事件放进监听数组
    nextListeners.push(listener)
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api-reference/store#subscribelistener for more details.'
        )
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
      currentListeners = null
    }
  }

这里面我们维护了一个nextListeners,它里面存放的就是监听的函数

这个函数监听忘了,那么就将他从数组里面删除

dispatch()

分发action的唯一方式

function dispatch(action) {
    //删去一些判断语句,这里只看逻辑部分
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
    return action
  }
  • 虽然dispatch传递的参数是action
  • 但是内部其实调用的是Reducer,传递参数currentStateaction
  • 按顺序执行listener,其实里面就是一个个的事件嘛?
  • 返回action

每次CreateStore()的时候,就会dispatch一个init Action,是为了生成初始化的State

总结:

第一次阅读redux,并对redux的工作流程有了一定的认识

之前也会使用redux,其实真的只会CV,这次不至于像之前那么困惑了

知道其实reudx内部由五个部分组成,其中createStore是主流程

CreateStore里面由于四个函数组成

这样一层层的看,其实还是很明了的

参考文章:
Redux从设计到源码 - 美团技术团队 (meituan.com)

学习 redux 源码整体架构,深入理解 redux 及其中间件原理 - 掘金 (juejin.cn)