您的位置:首页 > 其它

redux源码分析(三) 源码部分

2018-01-16 12:16 267 查看
源码结构

- /utils/

- actionTypes.js

- isPlainObject.js 判断是否是简单对象

- warning.js 一些警告在控制台打印

- applyMiddleware.js

- bindActionCreator.js

- combineReducer.js

- compose.js

- index.js

下面是每个部分的一些解读

- createStore

API
createStore(reducer, [initialState], enhancer)
,曾经非常好奇这个函数的第二个参数到底是initialState还是enhancer,因为见过两种写法都有的,以为是版本问题。看了源码才发现,都可以的。如果你不提供初始的state,可以直接把enhancer作为第二个参数传进去,这也是正常的

//API
....
import * as TodoActionCreators from './TodoActionCreators';

...
render() {
let boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
// {
//   addTodo: Function,
//   removeTodo: Function
// }
// 在子组件中直接 this.props.addTodo() 就相当于平时的 dispatch(addTodo())这样了
return (
<TodoList todos={todos}
{...boundActionCreators} />
);


若提供了enhancer则可对store进行一些增强

if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}


bindActionCreator

bindActionCreator通常是用来把dispatch传到子组件又不想被发现

//API
。。。。
import * as TodoActionCreators from './TodoActionCreators';

。。。
render() {
let boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
// {
//   addTodo: Function,
//   removeTodo: Function
// }
// 在子组件中直接 this.props.addTodo() 就相当于平时的 dispatch(addTodo())这样了
return (
<TodoList todos={todos}
{...boundActionCreators} />
);


源码部分

function bindActionCreator(actionCreator, dispatch) {
//对单个actionCreator进行dispatch
return function() {
return dispatch(actionCreator.apply(this, arguments))
}
}

export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
//actionCreators如果是一个对象就对每一个进行dispatch包装然后返回一个集合了包装的dispatch的对象
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}


applyMiddleware

//API
// 调用 applyMiddleware,使用 middleware 增强 createStore:
(1) let createStoreWithMiddleware = applyMiddleware(thunk)(createStore)
let reducer = combineReducers(reducers)
let store = createStoreWithMiddleware(reducer)


结合一些中间件,redux中约定了中间件的写法应该是这样的高阶函数
({dispatch}) => next => action => {...函数体}
。从下面源码中可以看到的,上面的(1)其实就是增强型store,通过传入默认的createStore方法创建一个store实例进而对dispatch进行改造,所谓的中间件就是一个不停对dispatch改造的过程

export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
let chain = []

const middlewareAPI = {
//每个中间件的一级那个参数都有这两个方法
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
//middlewares里面的每一项对是一个类似 (store) => dispatch => action =>{}的高阶函数
chain = middlewares.map(middleware => middleware(middlewareAPI));//这里我们把dispatch和getState传入高阶函数并运行一遍
//现在它们的返回值的每一项是一个(dispatch) => action =>{}的高阶函数了

//我们假设现在chain是[a,b],就是a、b两个中间件,a、b运行的返回值是dispatch
dispatch = compose(...chain)(store.dispatch)//dispatch 被改造了,所以可以dispatch一个函数
//dispatch = a(b(dispatch)),在这里,每一个前面中间件包装的dispatch会传入下一个中间件继续包装了
//dispatch(action) 相当于 a(b(dispatch))(action),也就是说 b的dispatch是原生的dispatch,a内的dispatch是经过b包装的
//也就是说,现在每dispatch一个action,都会去执行中间件里面的每一层的逻辑
return {
...store,
dispatch//这个把store中默认的dispatch覆盖掉
}
}
}


几个工具函数

isPlainObject

//判断是否是简单对象
//简单对象 通过{}或者new Object构造的
export default function isPlainObject(obj) {
if (typeof obj !== 'object' || obj === null) return false

let proto = obj
while (Object.getPrototypeOf(proto) !== null) {
//有两层原型就不是Object
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(obj) === proto
}


默认情况下action必须是简单对象而不能是函数,需要实现异步action时需要借助redux-thunk这个中间件才能来dispatch一个函数

compose

//compose
//通过数组的map方法实现类似 compose(f, g, h) 等于(...args) => f(g(h(...args)))的操作
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}

if (funcs.length === 1) {
return funcs[0]
}

return funcs.reduce((a, b) => (...args) => a(b(...args)))
}


ActionTypes.js

产生两个私有的action.type。用来初始化state和取代原有的reducer时又redux内部dispatch的

const ActionTypes = {
INIT:
'@@redux/INIT' +
Math.random()
.toString(36)
.substring(7)
.split('')
.join('.'),
REPLACE:
'@@redux/REPLACE' +
Math.random()
.toString(36)
.substring(7)
.split('')
.join('.')
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: