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
若提供了enhancer则可对store进行一些增强
bindActionCreator
bindActionCreator通常是用来把dispatch传到子组件又不想被发现
源码部分
applyMiddleware
结合一些中间件,redux中约定了中间件的写法应该是这样的高阶函数
几个工具函数
isPlainObject
默认情况下action必须是简单对象而不能是函数,需要实现异步action时需要借助redux-thunk这个中间件才能来dispatch一个函数
compose
ActionTypes.js
产生两个私有的action.type。用来初始化state和取代原有的reducer时又redux内部dispatch的
- /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('.') }
相关文章推荐
- 三星uboot1.1.6源码分析——start.s(6)--汇编部分完!
- 三星uboot1.1.6源码分析——start.s(8)--C语言部分(2)
- Java Collections Framework之Arrays(method:sort(),binarySearch(),copyOf())部分源码分析(基于JDK1.6)
- C#中Stack<T>类的使用及部分成员函数的源码分析
- Android TreeMap简要源码分析(先不涉及红黑树部分)
- freediameter部分源码分析
- input输入子系统源码部分函数分析
- Android Architecture Components 部分源码代码分析
- pixhawk(ArduCopter V3.3)源码分析—导航制导部分
- RocketMQ生产者消费者部分源码分析总结
- EasyJWeb-0.1.0部分源码分析
- nsq 源码分析之tcp协议部分
- 从Phone源码中分析来电话流程(部分)
- Ranklib部分源码分析
- Combres库 学习小结以及部分源码分析
- Android部分开源项目源码分析之---ViewBadge(View 上面动态的自定义的添加view)
- (转)Bootstrap 之 Metronic 模板的学习之路 - (2)源码分析之 head 部分
- 三星uboot1.1.6源码分析——start.s(10)--C语言部分(4)
- spring部分源码分析
- String的部分源码分析(substring、startsWith、endsWith)(一)