zhangyanan0525 / learn_summaries

就是个学习集锦
5 stars 0 forks source link

redux源码解析 #26

Open zhangyanan0525 opened 6 years ago

zhangyanan0525 commented 6 years ago

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

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](https://user-images.githubusercontent.com/20139082/54082667-2ba41c00-4354-11e9-9b05-a7a652f18033.png)
执行applyMiddleware后会return一个函数。也就是说传入createStore的是一个function。
![image](https://user-images.githubusercontent.com/20139082/54082686-a9682780-4354-11e9-9914-826ac29c8913.png)
符合途中黄色标记的if逻辑。那么传入的函数在createStore中叫做enhancer。
之后会走到执行逻辑中。
![image](https://user-images.githubusercontent.com/20139082/54082707-edf3c300-4354-11e9-901d-1a29b8c6279f.png)
可以看到,先把createStore传入执行一下,返回一个函数,然后又把reducer和preloadedState(如果有的话)传入执行。
![image](https://user-images.githubusercontent.com/20139082/54082814-04e6e500-4356-11e9-8334-147c64c84301.png)
第1步,还是先执行createStore生成一个store(我们上面已经分析过了)
第2步,执行每一个middleware函数,都会返回一个函数,组成数组chain。
第3步,chain传入compose函数,生成函数执行链。然后把参数dispatch传入,并且执行那个函数执行链。
最终,返回store和dispatch。此时的dispatch是改造后的,不是原来那个了。
## compose
神奇的compose函数,生成了函数执行链。仔细看下是怎么生成的
![image](https://user-images.githubusercontent.com/20139082/54082906-75423600-4357-11e9-8b08-0ec82ca4f3a6.png)
## bindActionCreators
一般情况下我们能在代码里直接用dispatch。但是redux还是提供了bindActionCreators。能让我们少写几个字的代码。
![image](https://user-images.githubusercontent.com/20139082/54083380-6cecf980-435d-11e9-8e51-e04b6eb64efb.png)
我们可以把actionCreators函数们组成的对象传入bindActionCreators。bindActionCreators做的就是生成一个新的对象boundActionCreators并return出去。boundActionCreators对象的key就是传入的actionCreator函数的名字,值就是新的函数function() {return dispatch(actionCreator.apply(this, arguments))}这样我们就不必显式的写那么多dispatch了哈哈。感觉还是很有用滴
zhangyanan0525 commented 5 years ago

中间件机制关键代码实现

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 commented 5 years ago

~~