Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redux源码解析 #26

Open
zhangyanan0525 opened this issue Oct 21, 2018 · 2 comments
Open

redux源码解析 #26

zhangyanan0525 opened this issue Oct 21, 2018 · 2 comments

Comments

@zhangyanan0525
Copy link
Owner

zhangyanan0525 commented Oct 21, 2018

redux源码解析

redux源码地址

redux主要代码的目录结构

image

接下来我们按照redux的官方网站提供的redux使用示例,来一步步看下每个函数的作用

根据示例,可以看出来,我们首先是定义许多actions,并且分别定义了两个reducer函数,然后通过combineReducers将两个reducer合并在一起,然后做为createStore的参数传入,并执行。
我看网上其他人的解析都是先分析createStore,但是我觉得应该从combineReducers开始。

combineReducers

image
重要的两行代码是:

import { combineReducers } from 'redux'
export default combineReducers({ todos, visibilityFilter })

我们根据这两行代码去找源码
image
image
我们找到了源码,原来就是这个combineReducers函数。我们看一下这个函数做了什么事情。(教大家一个小技巧,我们在看源码的时候,为了防止很多细节的代码,对主干代码的干扰,我们可以将大部分代码都合起来,需要看的时候再打开。)现在我们看到,combineReducers接受一个叫reducers的参数,返回一个闭包函数combination。
那么在返回这个combination函数之前,那一大坨代码干了什么事情呢?现在可以打开代码了,我们来看一下主要内容。

image
代码1部分,整个部分其实是为了生成一个finalReducers,让闭包使用。我们在使用redux的时候,单个reducer(todos, visibilityFilter)都应该定义成Function。这部分代码就是做了判断,看看这些单个reducer函数是不是undefined或是不是function,只有是function的才能幸运的进入finalReducers这个变量。
代码2部分大体就是一些数据格式的判断,有问题会报错。我没细看不影响大局。
好了我们再来看一遍redux官网给出的使用示例:
在reducers/index.js文件中,输出的其实就是combination闭包函数

export default combineReducers({ todos, visibilityFilter })

然后在index.js文件中,将combination函数起个名字rootReducer传入了createStore里。

import rootReducer from './reducers'
const store = createStore(rootReducer)

好。那么我们可以开始分析createStore了

createStore

我们还是把细节代码合上,只看主干
image

  • createStore函数,接收reducer, preloadedState, enhancer参数。代码1部分,主要是判断参数(多传了会报错。不传preloadedState也可以。不传enhancer也行,但是传了就得传函数,否则报错)。
  • 代码2部分,是设置了一些函数内的变量。为什么呢?因为代码3部分定义了几个Function,都是闭包,执行的时候会用到这些函数内的变量。
  • 代码3部分。getState函数可以读取当前store里的state。subscribe是可以暴露出来给别人用,监听state的变化(我们没直接用,因为react-redux替我们用了),ensureCanMutateNextListeners函数与监听器有关,但是是本函数内部用的,并没有暴露出去。dispatch函数就是我们脑子里那个dispatch,可以派发action那个。replaceReducer函数顾名思义,reducer改变时用,咱们那个热加载会用它。observable函数,我没找到哪里用它了,听说是测试代码里用了,那就不深究了。
  • 代码4部分就一句话 dispatch({ type: ActionTypes.INIT })。也就是执行了dispatch函数。让我们仔细看下dispatch的定义。
    image
    接收action做为参数,返回action。中间有一句代码比较关键currentState = currentReducer(currentState, action)。其实是执行了currentReducer函数,这个函数是谁呢?其实就是之前combineReducers返回的闭包函数combination。让我们看一下详细的定义
    image
    这个函数接收state和action,返回新的state。我们自己定义的actions里面并没有ActionTypes.INIT这个type,那为什么这里要执行呢?我自己跑了一个例子,从头debug了一次,发现这是要初始化state。生成了原始的store。这个过程是必须的。
  • 代码5部分,将各个函数的定义放到一个对象中return出来。
  • 走完了以上流程的我们,已经拥有了store了。可是还有其他函数没用用到,那它们是做什么的呢?我们继续分析
    image

applyMiddleware

先看官网是如何使用applyMiddleware的。

const logger = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

const crashReporter = store => next => action => {
  try {
    return next(action)
  } catch (err) {
    console.error('Caught an exception!', err)
    Raven.captureException(err, {
      extra: {
        action,
        state: store.getState()
      }
    })
    throw err
  }
}

import { createStore, combineReducers, applyMiddleware } from 'redux'

const todoApp = combineReducers(reducers)
const store = createStore(
  todoApp,
  // applyMiddleware() tells createStore() how to handle middleware
  applyMiddleware(logger, crashReporter)
)

可以看到,定义了两个插件logger,和crashReporter。做为applyMiddleware的参数传入并执行了applyMiddleware函数。把执行过后的结果传入了createStore做为第2个参数
image
执行applyMiddleware后会return一个函数。也就是说传入createStore的是一个function。
image
符合途中黄色标记的if逻辑。那么传入的函数在createStore中叫做enhancer。
之后会走到执行逻辑中。
image
可以看到,先把createStore传入执行一下,返回一个函数,然后又把reducer和preloadedState(如果有的话)传入执行。
image
第1步,还是先执行createStore生成一个store(我们上面已经分析过了)
第2步,执行每一个middleware函数,都会返回一个函数,组成数组chain。
第3步,chain传入compose函数,生成函数执行链。然后把参数dispatch传入,并且执行那个函数执行链。
最终,返回store和dispatch。此时的dispatch是改造后的,不是原来那个了。

compose

神奇的compose函数,生成了函数执行链。仔细看下是怎么生成的
image

bindActionCreators

一般情况下我们能在代码里直接用dispatch。但是redux还是提供了bindActionCreators。能让我们少写几个字的代码。
image
我们可以把actionCreators函数们组成的对象传入bindActionCreators。bindActionCreators做的就是生成一个新的对象boundActionCreators并return出去。boundActionCreators对象的key就是传入的actionCreator函数的名字,值就是新的函数function() {return dispatch(actionCreator.apply(this, arguments))}这样我们就不必显式的写那么多dispatch了哈哈。感觉还是很有用滴

@zhangyanan0525 zhangyanan0525 changed the title 学习redux redux源码解析 Mar 9, 2019
@zhangyanan0525
Copy link
Owner Author

zhangyanan0525 commented Mar 22, 2019

中间件机制关键代码实现

let funcs = [
    (next)=>(action)=>{console.log(1);next(action);console.log(2)},
    (next)=>(action)=>{console.log(3);next(action);console.log(4)}
]
let dispatch = (action)=>{
    console.log(action)
}
const compose = function(funcs){
    return funcs.reduce((a,b)=>{
        return (dispatch)=>a(b(dispatch))
    })
}
dispatch = compose(funcs)(dispatch)
dispatch('我派发了action')

@JserJser
Copy link

~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants