日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redux 和 react-redux 部分源码阅读

發(fā)布時間:2025/6/17 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redux 和 react-redux 部分源码阅读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

從源代碼的入口文件發(fā)現,其實 redux 最終就只是導出了一個對象,對象中有幾個方法,代碼如下:

export {createStore,combineReducers,bindActionCreators,applyMiddleware,compose,__DO_NOT_USE__ActionTypes } 復制代碼

所以重點分析幾個方法:

createStore 方法

方法中定義的一些變量:

let currentReducer = reducer let currentState = preloadedState let currentListeners = [] let nextListeners = currentListeners let isDispatching = false 復制代碼

這些變量會被 dispatch 或者別的方法引用,從而形成閉包。這些變量不會被釋放。

創(chuàng)建 srore 的方法最終返回的是一個對象。對象中含有比較重要的方法dispatch,subscribe,getState。

return {dispatch,subscribe,getState,replaceReducer,[$$observable]: observable } 復制代碼

其中 createStore 的第三個參數是應用中間件來做一些增強操作的。

if (typeof enhancer !== 'undefined') { // 如果增強方法存在就對 createStore 進行增強if (typeof enhancer !== 'function') {throw new Error('Expected the enhancer to be a function.')}return enhancer(createStore)(reducer, preloadedState) } 復制代碼

subscribe 方法

其中 subscribe 用來注冊監(jiān)聽方法,每一次注冊后會將監(jiān)聽方法維護到數組currentListeners中,currentListeners 是 createStore 中的一個變量,由于被 subscribe 引用著所以形成了一個閉包。也就是通過閉包來維護狀態(tài)。

let currentListeners = [] 復制代碼

dispatch 方法

dispatch 方法用來分發(fā) action, 函數里面會生成新的 currentState, 會執(zhí)行所有注冊了的函數。

核心代碼:

try {isDispatching = truecurrentState = currentReducer(currentState, action) // 生成新的 state } finally {isDispatching = false }const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) {const listener = listeners[i]listener() } // 遍歷執(zhí)行注冊函數 復制代碼

getState

僅僅用來獲得當前的 state:

function getState() {return currentState } 復制代碼

combineReducers 函數

函數中定義的一些變量,

const finalReducers = {} const finalReducerKeys = Object.keys(finalReducers) 復制代碼

這個函數最后返回的是一個函數 combination, 返回的函數中引用了 finalReducers 和 finalReducerKeys,形成了閉包。

出于業(yè)務場景考慮,不同的模塊采用不同的 reducer 進行處理,所以 reducer 函數有很多。這些 reducer 會遍歷執(zhí)行。

每一次 dispatch 一個 action 的時候就會執(zhí)行

currentState = currentReducer(currentState, action) // 生成新的 state 復制代碼

這里的 currentReducer 就是返回的 combination 函數。combination 函數中的核心代碼:

function combination(state = {}, action) {...let hasChanged = false// 每一次 reducer 執(zhí)行的時候都會生成一個新的對象來作為新的 state const nextState = {}// 通過 for 循環(huán)遍歷 reducer for (let i = 0; i < finalReducerKeys.length; i++) {const key = finalReducerKeys[i]const reducer = finalReducers[key]// 獲取當前的 stateconst previousStateForKey = state[key]// 執(zhí)行相應的 reducer 后會生成新的 stateconst nextStateForKey = reducer(previousStateForKey, action)if (typeof nextStateForKey === 'undefined') {const errorMessage = getUndefinedStateErrorMessage(key, action)throw new Error(errorMessage)}// 給新的 state 賦值nextState[key] = nextStateForKey// 如果是一個簡單類型比如 string,number // 如果前后值一樣就不會觸發(fā)改變// 但如果 state 中某個值是一個對象,// 盡管前后對象中的值一樣,但是引用地址變化,還是會觸發(fā)改變hasChanged = hasChanged || nextStateForKey !== previousStateForKey}// 所以如果簡單值沒有變化并且沒有對象的引用地址改變就會返回原來的 statereturn hasChanged ? nextState : state } 復制代碼

結合 react-redux 中向 redux 訂閱的方法發(fā)現

subscribe() {const { store } = this.props // 這里的 store 是 createStore 方法執(zhí)行后返回的對象this.unsubscribe = store.subscribe(() => { // 通過訂閱方法注冊監(jiān)聽事件const newStoreState = store.getState() // 獲取新的 stateif (!this._isMounted) {return}// 通過使用函數替代對象傳入 setState 的方式能夠得到組件的 state 和 props 屬性可靠的值。this.setState(providerState => {// 如果值是一樣的就不會觸發(fā)更新if (providerState.storeState === newStoreState) {return null}return { storeState: newStoreState }})})// Actions might have been dispatched between render and mount - handle thoseconst postMountStoreState = store.getState()if (postMountStoreState !== this.state.storeState) {this.setState({ storeState: postMountStoreState })} } 復制代碼

在注冊的 listen 方法中會發(fā)現如果最 新的state和原來的state一樣 就不會觸發(fā) setState 方法的執(zhí)行,從而就不會觸發(fā) render。

applyMiddleware 使用中間件

源碼:

export default function applyMiddleware(...middlewares) {return createStore => (...args) => { // 接收 createStore 函數作為參數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.`)}const middlewareAPI = {getState: store.getState,dispatch: (...args) => dispatch(...args)} // 中間件函數接收的 API 參數,能夠獲取到當前的 state 和 createStore 函數的參數// 所以這里就向中間件函數中傳遞了參數const chain = middlewares.map(middleware => middleware(middlewareAPI))// 通過函數組合生成一個新的 dispatch 函數dispatch = compose(...chain)(store.dispatch)return {...store,dispatch} // 這里返回的是最后生成的 store,相比不使用中間件的區(qū)別是對 dispatch 進行了增強。} } 復制代碼

結合 createStore 中的源碼:

return enhancer(createStore)(reducer, preloadedState) 復制代碼

所以上面 applyMiddleware 中返回的函數就是這里的 enhancer 方法,接收 createStore 作為參數。

(reducer, preloadedState) 對應著中間件中的 (...args)。

react-redux

react-redux 通過提供 Provider 組件將 store 和整個應用中的組件聯系起來。確保整個組件都可以獲得 store, 這是通過 Context 來實現的。

Provider 組件最終渲染的組件:

render() {const Context = this.props.context || ReactReduxContextreturn (<Context.Provider value={this.state}>{this.props.children}</Context.Provider>) } 復制代碼

其中 state 的定義如下:

const { store } = props this.state = {storeState: store.getState(),store } 復制代碼

所以 Provider 給應用提供 store 的寫法如下,屬性名必須是 store。

<Provider store={store}><Router /> </Provider> 復制代碼

redux-thunk

redux-thunk 是一個中間件,直接看中間件的源代碼是絕對不可能看明白的。

中間件不是一個完整的個體。它是為了豐富或者擴展某個模塊而出現的,其中會調用一些原來的模塊的方法,所以如果不看源模塊的對應的方法實現,根本無法理解。

所以要想看懂一個中間件,必須結合源模塊的代碼一起看。

Thunk 函數的含義和用法

JavaScript 語言是傳值調用,它的 Thunk 函數含義有所不同。在 JavaScript 語言中,Thunk 函數替換的不是表達式,而是多參數函數,將其替換成單參數的版本,且只接受回調函數作為參數

如何讓 dispatch 分發(fā)一個函數,也就是 action creator??

dispatch 的參數只能是一個普通的對象,如果要讓參數是一個函數,需要使用中間件 redux-thunk。

設計思想就是一種面向切面編程AOP,對函數行為的增強,也是裝飾模式的使用。

redux-thunk 源碼:

function createThunkMiddleware(extraArgument) {return ({ dispatch, getState }) => next => action => {if (typeof action === 'function') {return action(dispatch, getState, extraArgument);}return next(action);}; }const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;export default thunk; 復制代碼

如果只是用了 thunk,那么最終增強版的 dispatch 就是

action => {// 當 dispatch 參數是一個函數的時候執(zhí)行這里if (typeof action === 'function') { // 這里的 dispatch 就是最原始的 dispatch// 所以 action 函數中可以直接使用參數 dispatch 和 getState 函數return action(dispatch, getState, extraArgument);}return next(action); // 這里的 next 是 store.dispatch } 復制代碼

異步操作帶代碼

異步操作如果使用 action creator, 則至少要送出兩個 Action:

  • 用戶觸發(fā)第一個 Action,這個跟同步操作一樣,沒有問題;
  • 在 action creator 函數中送出第二個 Action

代碼實例:

handleClick = () => {const { dispatch } = this.propsdispatch(this.action); // 發(fā)出第一個 action(函數) }action = (dispatch, getState) => setTimeout(() => {dispatch({ type: 'REQUESTSTART' }) }, 1000) // 發(fā)出第二個 action(普通對象) 復制代碼

思考

異步代碼的處理一定要使用 redux-thunk嗎?

非也。在觸發(fā)含有異步代碼的函數執(zhí)行時,把 dispatch 函數作為一個參數傳給函數,然后這個異步函數里面在合適的時機調用 dispatch 發(fā)出 action 就行。

上面的異步代碼可改寫如下:

handleClick = () => {const { dispatch } = this.propsthis.action(dispatch); }action = dispatch => setTimeout(() => {dispatch({ type: 'REQUESTSTART' }) }, 1000) 復制代碼

不過相比 redux-thunk 有個缺陷就是不能獲取 getState 這個方法。

使用示例

使用 redux 演示代碼

轉載于:https://juejin.im/post/5c26e210e51d45342a255ad2

《新程序員》:云原生和全面數字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的redux 和 react-redux 部分源码阅读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。