摘要:源碼解讀的方法就是給我們提供了靈活的創(chuàng)建符合標準的的方法。用于分解樹,每一個對應的一個對應的子。這樣在將傳遞給時利于分解。源碼實現(xiàn)了這種將函數(shù)數(shù)組,通過的方法,實現(xiàn)層層嵌套的執(zhí)行,達到中間件的實現(xiàn)。
Redux 源碼解讀 1.redux-action createAction
redux-action的createAction方法就是給我們提供了靈活的創(chuàng)建符合FSA標準的action的方法。
exports.default = createAction; /** 返回創(chuàng)建action的函數(shù) */ function createAction(type, payloadCreator, metaCreator) { var finalPayloadCreator = typeof payloadCreator === "function" ? payloadCreator : _identity2.default; /** 返回的函數(shù) */ var actionHandler = function actionHandler() { var hasError = (arguments.length <= 0 ? undefined : arguments[0]) instanceof Error; /** 返回的action */ var action = { type: type }; //根據(jù)傳入的參數(shù),執(zhí)行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; } //根據(jù)傳入的參數(shù),執(zhí)行metaCreator獲取payload if (typeof metaCreator === "function") { action.meta = metaCreator.apply(undefined, arguments); } //可以看到 payloadCreator和metaCreator的參數(shù)都是用的傳給actionHandler的參數(shù) return action; }; actionHandler.toString = function () { return type.toString(); }; return actionHandler; }2.redux combineReducer
redux的combineReducer方法 用于將多個reducer,合并成一個大的reducer函數(shù),傳給store。
用于分解state樹,每一個reducer對應state的一個key對應的子state。比如poi的reducer對應的就是state[poi]。這樣在將state傳遞給props時利于分解。
reducer以對象的形式傳入,finalReducers 存放最終的reducer,finalReducerKeys存放reducer的key 最終返回 combination函數(shù) reducer類型的函數(shù),接受state和action 返回state state的形式是一個大對象下面每一個reducer對應一個子state。 觸發(fā)一個action,會遍歷所有的reducer, 將該reducer的舊state和action傳入,然后根據(jù)返回的新的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執(zhí)行之前,需要經(jīng)過中間件的層層處理,進行一些業(yè)務上的處理,決定action的走向。
源碼實現(xiàn)了這種將函數(shù)數(shù)組,通過reducerRight的方法,實現(xiàn)層層嵌套的執(zhí)行,達到中間件的實現(xiàn)。
/** 顯示執(zhí)行中間件,得到中間件的返回函數(shù)數(shù)組chain,然后利用compose方法,生成嵌套的執(zhí)行chain 方法的包裝dispatch函數(shù), 中間件的形式是 (getState, dispatch)=> next => action => { next(action); } */ export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, 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傳入后返回的函數(shù)就是我們需要的函數(shù)形式, 例如dispatch 需要的函數(shù)形式是 傳一個action */ return { ...store, dispatch } } } /** reduceRight是數(shù)組的從右至左執(zhí)行, 初始的參數(shù)是最后一個函數(shù)接受dispatch, 的到的一個action=>{ dispatch(action); } 形式的函數(shù),作為參數(shù)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)) }
中間件執(zhí)行過程模擬
中間件原理 */ 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"); /** 執(zhí)行順序 func3 return func2 return func1 return func1start func2start func3start action func3end func2end func1end */4 redux createStore
應用場景參見中間件的應用代碼與applyMiddleware源碼,是redux提供創(chuàng)建store的方法。
import isPlainObject from "lodash/isPlainObject" import $$observable from "symbol-observable" export var ActionTypes = { INIT: "@@redux/INIT" } export default function createStore(reducer, preloadedState, 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 } /** 訂閱監(jiān)聽 */ 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) } } /** 執(zhí)行reducer,獲取state,執(zhí)行l(wèi)istener */ 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創(chuàng)建的時候,獲取初始的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
能夠監(jiān)聽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 = {}) { //返回包裝組件的函數(shù) 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,觸發(fā)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的非靜態(tài)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 }
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80813.html
摘要:的中間件主要是通過模塊實現(xiàn)的。返回的也是一個對象這個其實就是,各個中間件的最底層第三層的哪個函數(shù)組成的圓環(huán)函數(shù)構成的這就是對源碼的一個整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測試例子可以關注源碼解讀倉庫 applyMiddleware源碼解析 中間件機制在redux中是強大且便捷的,利用redux的中間件我們能夠實現(xiàn)日志記錄,異步調用等多種十分實用的功能。redux的中間件主要是...
摘要:這里還有一個疑問點就是的嵌套,最開始也我不明白,看了源碼才知道,這里返回的也是接受也就是一個所以可以正常嵌套。以作為參數(shù),調用上一步返回的函數(shù)以為參數(shù)進行調用。 1、本文不涉及redux的使用方法,因此可能更適合使用過 redux 的同學閱讀2、當前redux版本為4.0.13、更多系列文章請看 Redux作為大型React應用狀態(tài)管理最常用的工具。雖然在平時的工作中很多次的用到了它...
摘要:源碼解析模塊的代碼十分簡練,但是實現(xiàn)的作用卻是十分強大。只傳遞一個參數(shù)的時候,就直接把這個函數(shù)返回返回組合函數(shù)這就是對源碼的一個整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測試例子可以關注源碼解讀倉庫 compose源碼解析 compose模塊的代碼十分簡練,但是實現(xiàn)的作用卻是十分強大。redux為何稱為redux?有人說就是reduce和flux的結合體,而reduce正是comp...
閱讀 1629·2019-08-30 15:54
閱讀 2374·2019-08-30 15:52
閱讀 2048·2019-08-29 15:33
閱讀 3042·2019-08-28 17:56
閱讀 3238·2019-08-26 13:54
閱讀 1675·2019-08-26 12:16
閱讀 2449·2019-08-26 11:51
閱讀 1645·2019-08-26 10:26