Redux 源码解读
1.redux-action createAction
redux-action的createAction方法就是给我们提供了灵活的创建符合FSA标准的action的方法。
exports.default = createAction; /** 返回创建action的函数 */ function createAction(type,payloadCreator,MetaCreator) { var finalPayloadCreator = typeof payloadCreator === 'function' ? payloadCreator : _identity2.default; /** 返回的函数 */ var actionHandler = function actionHandler() { var hasError = (arguments.length <= 0 ? undefined : arguments[0]) instanceof Error; /** 返回的action */ var action = { type: type }; //根据传入的参数,执行payloadCreator获取payload var payload = hasError ? arguments.length <= 0 ? undefined : arguments[0] : finalPayloadCreator.apply(undefined,arguments); if (!(payload === null || payload === undefined)) { action.payload = payload; } if (hasError) { // Handle FSA errors where the payload is an Error object. Set error. action.error = true; } //根据传入的参数,执行MetaCreator获取payload if (typeof MetaCreator === 'function') { action.Meta = MetaCreator.apply(undefined,arguments); } //可以看到 payloadCreator和MetaCreator的参数都是用的传给actionHandler的参数 return action; }; actionHandler.toString = function () { return type.toString(); }; return actionHandler; }
2.redux combineReducer
redux的combineReducer方法 用于将多个reducer,合并成一个大的reducer函数,传给store。
用于分解state树,每一个reducer对应state的一个key对应的子state。比如poi的reducer对应的就是state[poi]。这样在将state传递给props时利于分解。
reducer以对象的形式传入,finalReducers 存放最终的reducer,finalReducerKeys存放reducer的key 最终返回 combination函数 reducer类型的函数,接受state和action 返回state state的形式是一个大对象下面每一个reducer对应一个子state。 触发一个action,会遍历所有的reducer, 将该reducer的旧state和action传入,然后根据返回的新的state对象是否改变,来决定 最终的返回的state是否改变。 这里需要注意:由于state都是引用类型,这里比较是值比较 hasChanged = hasChanged || nextStateForKey !== prevIoUsStateForKey 所以如果我们想要改变全局的state,需要在reducer中返回新的对象,而不是原来的state对象, 如果返回原来的对象,即使对象里的值改变了,也不会引起全局state的改变。 */ export default function combineReducers(reducers) { var reducerKeys = Object.keys(reducers) var finalReducers = {} for (var i = 0; i < reducerKeys.length; i++) { var key = reducerKeys[i] if (process.env.NODE_ENV !== 'production') { if (typeof reducers[key] === 'undefined') { warning(`No reducer provided for key "${key}"`) } } if (typeof reducers[key] === 'function') { finalReducers[key] = reducers[key] } } var finalReducerKeys = Object.keys(finalReducers) return function combination(state = {},action) { /** 校验语法错误,reducer返回的state不能是undefined */ if (sanityError) { throw sanityError } var hasChanged = false var nextState = {} for (var i = 0; i < finalReducerKeys.length; i++) { var key = finalReducerKeys[i] var reducer = finalReducers[key] var prevIoUsStateForKey = state[key] var nextStateForKey = reducer(prevIoUsStateForKey,action) if (typeof nextStateForKey === 'undefined') { var errorMessage = getUndefinedStateErrorMessage(key,action) throw new Error(errorMessage) } nextState[key] = nextStateForKey /** 所以如果我们想要改变全局的state,需要在reducer中返回新的对象,而不是原来的state对象, 如果返回原来的对象,即使对象里的值改变了,也不会引起全局state的改变。 */ hasChanged = hasChanged || nextStateForKey !== prevIoUsStateForKey } return hasChanged ? nextState : state } }
3 redux applyMiddleware
应用中间件的目的是包装dispatch,在action传递给dispatch执行之前,需要经过中间件的层层处理,进行一些业务上的处理,决定action的走向。
源码实现了这种将函数数组,通过reducerRight的方法,实现层层嵌套的执行,达到中间件的实现。
/** 显示执行中间件,得到中间件的返回函数数组chain,然后利用compose方法,生成嵌套的执行chain 方法的包装dispatch函数, 中间件的形式是 (getState,dispatch)=> next => action => { next(action); } */ export default function applyMiddleware(...middlewares) { return (createStore) => (reducer,preloadedState,enhancer) => { var store = createStore(reducer,enhancer) var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState,dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) /** store.dispatch 就是第一个next 是last ware的next (...args) => { return ware0(ware1(ware2(last(...args)))) } dispatch = ware0(ware1(ware2(last(...args)))) 所以中间件中next传入后返回的函数就是我们需要的函数形式, 例如dispatch 需要的函数形式是 传一个action */ return { ...store,dispatch } } } /** reduceRight是数组的从右至左执行, 初始的参数是最后一个函数接受dispatch, 的到的一个action=>{ dispatch(action); } 形式的函数,作为参数composed f的形式是 next=>action=>{ } 最终形成的就是 (...args) => { return funcs0(funcs1(funcs2(last(...args)))) } */ export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } const last = funcs[funcs.length - 1] const rest = funcs.slice(0,-1) return (...args) => rest.reduceRight((composed,f) => f(composed),last(...args)) }
中间件执行过程模拟
中间件原理 */ function func1 (next) { console.log('func1 return'); return function (action) { console.log('func1start'); next(action); console.log('func1end'); } } function func2 (next) { console.log('func2 return'); return function (action) { console.log('func2start'); next(action); console.log('func2end'); } } function func3 (next) { console.log('func3 return'); return function (action) { console.log('func3start'); next(action); console.log('func3end'); } } function dispatch(action) { console.log(action); } function afterCompose (args) { return func1(func2(func3(args))); } var newdispatch = afterCompose(dispatch); newdispatch('action'); /** 执行顺序 func3 return func2 return func1 return func1start func2start func3start action func3end func2end func1end */
4 redux createStore
应用场景参见中间件的应用代码与applyMiddleware源码,是redux提供创建store的方法。
import isPlainObject from 'lodash/isPlainObject' import $$observable from 'symbol-observable' export var ActionTypes = { INIT: '@@redux/INIT' } export default function createStore(reducer,enhancer) { var currentReducer = reducer var currentState = preloadedState var currentListeners = [] var nextListeners = currentListeners var isDispatching = false function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } } function getState() { return currentState } /** 订阅监听 */ function subscribe(listener) { if (typeof listener !== 'function') { throw new Error('Expected listener to be a function.') } var isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) return function unsubscribe() { if (!isSubscribed) { return } isSubscribed = false ensureCanMutateNextListeners() var index = nextListeners.indexOf(listener) nextListeners.splice(index,1) } } /** 执行reducer,获取state,执行listener */ function dispatch(action) { try { isDispatching = true currentState = currentReducer(currentState,action) } finally { isDispatching = false } var listeners = currentListeners = nextListeners for (var i = 0; i < listeners.length; i++) { listeners[i]() } return action } /** 替换reducer */ function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer dispatch({ type: ActionTypes.INIT }) } /** store创建的时候,获取初始的sate树 */ dispatch({ type: ActionTypes.INIT }) return { dispatch,subscribe,getState,replaceReducer } }
5. react-redux Provider
redux和react的结合,Provider作为根组件,将store的state放在context中供子组件使用。
import { Component,PropTypes,Children } from 'react' import storeShape from '../utils/storeShape' import warning from '../utils/warning' export default class Provider extends Component { //把 store 放在context里面,给子元素用 getChildContext() { return { store: this.store } } constructor(props,context) { super(props,context) this.store = props.store } render() { const { children } = this.props //渲染唯一的子元素 return Children.only(children) } } Provider.propTypes = { store: storeShape.isrequired,children: PropTypes.element.isrequired } Provider.childContextTypes = { store: storeShape.isrequired }
6. react-redux connect
connect方法,将React的组件进行包装,包装的目的如下:
能够将store中指定的state,传递给组件当props
能够监听store中state的变化
能够将action传递给view
const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars const defaultMapDispatchToProps = dispatch => ({ dispatch }) const defaultMergeProps = (stateProps,dispatchProps,parentProps) => ({ ...parentProps,...stateProps,...dispatchProps }) export default function connect(mapStateToProps,mapDispatchToProps,mergeProps,options = {}) { //返回包装组件的函数 return function wrapWithConnect(WrappedComponent) { class Connect extends Component { shouldComponentUpdate() { return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged } constructor(props,context) { super(props,context) this.version = version this.store = props.store || context.store const storeState = this.store.getState() this.state = { storeState } this.clearCache() } isSubscribed() { return typeof this.unsubscribe === 'function' } trySubscribe() { if (shouldSubscribe && !this.unsubscribe) { //订阅store的state变化 this.unsubscribe = this.store.subscribe(this.handleChange.bind(this)) this.handleChange() } } tryUnsubscribe() { if (this.unsubscribe) { this.unsubscribe() this.unsubscribe = null } } componentDidMount() { //订阅store的state变化 this.trySubscribe() } componentWillReceiveProps(nextProps) { if (!pure || !shallowEqual(nextProps,this.props)) { this.haveOwnPropsChanged = true } } componentWillUnmount() { this.tryUnsubscribe() this.clearCache() } //订阅变化 handleChange() { if (!this.unsubscribe) { return } const storeState = this.store.getState() const prevStoreState = this.state.storeState if (pure && prevStoreState === storeState) { return } if (pure && !this.doStatePropsDependOnOwnProps) { const haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded,this) if (!haveStatePropsChanged) { return } if (haveStatePropsChanged === errorObject) { this.statePropsPrecalculationError = errorObject.value } this.haveStatePropsBeenPrecalculated = true } this.hasStoreStateChanged = true //如果有变化 setState,触发render this.setState({ storeState }) } render() { const { haveOwnPropsChanged,hasStoreStateChanged,haveStatePropsBeenPrecalculated,statePropsPrecalculationError,renderedElement } = this //最终渲染组件,将合并属性传递给WrappedComponent if (withRef) { this.renderedElement = createElement(WrappedComponent,{ ...this.mergedProps,ref: 'wrappedInstance' }) } else { this.renderedElement = createElement(WrappedComponent,this.mergedProps ) } return this.renderedElement } } Connect.displayName = connectDisplayName Connect.WrappedComponent = WrappedComponent Connect.contextTypes = { store: storeShape } Connect.propTypes = { store: storeShape } //把WrappedComponent的非静态react属性 复制到Connect,最终返回Connect return hoistStatics(Connect,WrappedComponent) } }
7. redux bindActionCreators
使用实例参见 react-redux connect 的使用实例
function bindActionCreator(actionCreator,dispatch) { return (...args) => dispatch(actionCreator(...args)) } 将actionCreators绑定上dispatch,key还是actionCreators的key,但是多做了一层dispatch */ export default function bindActionCreators(actionCreators,dispatch) { if (typeof actionCreators === 'function') { return bindActionCreator(actionCreators,dispatch) } if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error( `bindActionCreators expected an object or a function,instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` + `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?` ) } var keys = Object.keys(actionCreators) var boundActionCreators = {} for (var i = 0; i < keys.length; i++) { var key = keys[i] var actionCreator = actionCreators[key] if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator,dispatch) } } return boundActionCreators }原文链接:https://www.f2er.com/react/305531.html