91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么理解Redux原理

發布時間:2021-11-02 16:29:23 來源:億速云 閱讀:148 作者:iii 欄目:web開發

這篇文章主要介紹“怎么理解Redux原理”,在日常操作中,相信很多人在怎么理解Redux原理問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么理解Redux原理”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

基本概念

Redux的概念有很多文章都講過,想必大家都看過很多了,我這里不再展開,只是簡單提一下。Redux基本概念主要有以下幾個:

Store

人如其名,Store就是一個倉庫,它存儲了所有的狀態(State),還提供了一些操作他的API,我們后續的操作其實都是在操作這個倉庫。假如我們的倉庫是用來放牛奶的,初始情況下,我們的倉庫里面一箱牛奶都沒有,那Store的狀態(State)就是:

{      milk: 0  }

Actions

一個Action就是一個動作,這個動作的目的是更改Store中的某個狀態,Store還是上面的那個倉庫,現在我想往倉庫放一箱牛奶,那"我想往倉庫放一箱牛奶"就是一個Action,代碼就是這樣:

{    type: "PUT_MILK",    count: 1  }

Reducers

前面"我想往倉庫放一箱牛奶"只是想了,還沒操作,具體操作要靠Reducer,Reducer就是根據接收的Action來改變Store中的狀態,比如我接收了一個PUT_MILK,同時數量count是1,那放進去的結果就是milk增加了1,從0變成了1,代碼就是這樣:

const initState = {    milk: 0  }  function reducer(state = initState, action) {    switch (action.type) {      case 'PUT_MILK':        return {...state, milk: state.milk + action.count}      default:        return state    }  }

可以看到Redux本身就是一個單純的狀態機,Store存放了所有的狀態,Action是一個改變狀態的通知,Reducer接收到通知就更改Store中對應的狀態。

簡單例子

下面我們來看一個簡單的例子,包含了前面提到的Store,Action和Reducer這幾個概念:

import { createStore } from 'redux';  const initState = {    milk: 0  };  function reducer(state = initState, action) {    switch (action.type) {      case 'PUT_MILK':        return {...state, milk: state.milk + action.count};      case 'TAKE_MILK':        return {...state, milk: state.milk - action.count};      default:        return state;    }  }  let store = createStore(reducer);  // subscribe其實就是訂閱store的變化,一旦store發生了變化,傳入的回調函數就會被調用  // 如果是結合頁面更新,更新的操作就是在這里執行  store.subscribe(() => console.log(store.getState()));  // 將action發出去要用dispatch  store.dispatch({ type: 'PUT_MILK' });    // milk: 1  store.dispatch({ type: 'PUT_MILK' });    // milk: 2  store.dispatch({ type: 'TAKE_MILK' });   // milk: 1

自己實現

前面我們那個例子雖然短小,但是已經包含了Redux的核心功能了,所以我們手寫的第一個目標就是替換這個例子中的Redux。要替換這個Redux,我們得先知道他里面都有什么東西,仔細一看,我們好像只用到了他的一個API:

createStore:這個API接受reducer方法作為參數,返回一個store,主要功能都在這個store上。

看看store上我們都用到了啥:

store.subscribe: 訂閱state的變化,當state變化的時候執行回調,可以有多個subscribe,里面的回調會依次執行。

store.dispatch: 發出action的方法,每次dispatch action都會執行reducer生成新的state,然后執行subscribe注冊的回調。

store.getState:一個簡單的方法,返回當前的state。

看到subscribe注冊回調,dispatch觸發回調,想到了什么,這不就是發布訂閱模式嗎?我之前有一篇文章詳細講過發布訂閱模式了,這里直接仿寫一個。

function createStore() {    let state;              // state記錄所有狀態    let listeners = [];     // 保存所有注冊的回調    function subscribe(callback) {      listeners.push(callback);       // subscribe就是將回調保存下來    }    // dispatch就是將所有的回調拿出來依次執行就行    function dispatch() {      for (let i = 0; i < listeners.length; i++) {        const listener = listeners[i];        listener();      }    }    // getState直接返回state    function getState() {      return state;    }    // store包裝一下前面的方法直接返回    const store = {      subscribe,      dispatch,      getState    }    return store;  }

上述代碼是不是很簡單嘛,Redux核心也是一個發布訂閱模式,就是這么簡單!等等,好像漏了啥,reducer呢?reducer的作用是在發布事件的時候改變state,所以我們的dispatch在執行回調前應該先執行reducer,用reducer的返回值重新給state賦值,dispatch改寫如下:

function dispatch(action) {    state = reducer(state, action);    for (let i = 0; i < listeners.length; i++) {      const listener = listeners[i];      listener();    }  }

到這里,前面例子用到的所有API我們都自己實現了,我們用自己的Redux來替換下官方的Redux試試:

// import { createStore } from 'redux';  import { createStore } from './myRedux';

可以看到輸出結果是一樣的,說明我們自己寫的Redux沒有問題:

怎么理解Redux原理

了解了Redux的核心原理,我們再去看他的源碼應該就沒有問題了,createStore的源碼傳送門。

最后我們再來梳理下Redux的核心流程,注意單純的Redux只是個狀態機,是沒有View層的哦。

怎么理解Redux原理

除了這個核心邏輯外,Redux里面還有些API也很有意思,我們也來手寫下。

手寫combineReducers

combineReducers也是使用非常廣泛的API,當我們應用越來越復雜,如果將所有邏輯都寫在一個reducer里面,最終這個文件可能會有成千上萬行,所以Redux提供了combineReducers,可以讓我們為不同的模塊寫自己的reducer,最終將他們組合起來。比如我們最開始那個牛奶倉庫,由于我們的業務發展很好,我們又增加了一個放大米的倉庫,我們可以為這兩個倉庫創建自己的reducer,然后將他們組合起來,使用方法如下:

import { createStore, combineReducers } from 'redux';  const initMilkState = {    milk: 0  };  function milkReducer(state = initMilkState, action) {    switch (action.type) {      case 'PUT_MILK':        return {...state, milk: state.milk + action.count};      case 'TAKE_MILK':        return {...state, milk: state.milk - action.count};      default:        return state;    }  }  const initRiceState = {    rice: 0  };  function riceReducer(state = initRiceState, action) {    switch (action.type) {      case 'PUT_RICE':        return {...state, rice: state.rice + action.count};      case 'TAKE_RICE':        return {...state, rice: state.rice - action.count};      default:        return state;    }  }  // 使用combineReducers組合兩個reducer  const reducer = combineReducers({milkState: milkReducer, riceState: riceReducer});  let store = createStore(reducer);  store.subscribe(() => console.log(store.getState()));  // 操作?的action  store.dispatch({ type: 'PUT_MILK', count: 1 });    // milk: 1  store.dispatch({ type: 'PUT_MILK', count: 1 });    // milk: 2  store.dispatch({ type: 'TAKE_MILK', count: 1 });   // milk: 1  // 操作大米的action  store.dispatch({ type: 'PUT_RICE', count: 1 });    // rice: 1  store.dispatch({ type: 'PUT_RICE', count: 1 });    // rice: 2  store.dispatch({ type: 'TAKE_RICE', count: 1 });   // rice: 1

上面代碼我們將大的state分成了兩個小的milkState和riceState,最終運行結果如下:

怎么理解Redux原理

知道了用法,我們嘗試自己來寫下呢!要手寫combineReducers,我們先來分析下他干了啥,首先它的返回值是一個reducer,這個reducer同樣會作為createStore的參數傳進去,說明這個返回值是一個跟我們之前普通reducer結構一樣的函數。這個函數同樣接收state和action然后返回新的state,只是這個新的state要符合combineReducers參數的數據結構。我們嘗試來寫下:

function combineReducers(reducerMap) {    const reducerKeys = Object.keys(reducerMap);    // 先把參數里面所有的鍵值拿出來    // 返回值是一個普通結構的reducer函數    const reducer = (state = {}, action) => {      const newState = {};        for(let i = 0; i < reducerKeys.length; i++) {        // reducerMap里面每個鍵的值都是一個reducer,我們把它拿出來運行下就可以得到對應鍵新的state值        // 然后將所有reducer返回的state按照參數里面的key組裝好        // 最后再返回組裝好的newState就行        const key = reducerKeys[i];        const currentReducer = reducerMap[key];        const prevState = state[key];        newState[key] = currentReducer(prevState, action);      }       return newState;    };     return reducer;  }

官方源碼的實現原理跟我們的一樣,只是他有更多的錯誤處理,大家可以對照著看下。

手寫applyMiddleware

middleware是Redux里面很重要的一個概念,Redux的生態主要靠這個API接入,比如我們想寫一個logger的中間件可以這樣寫(這個中間件來自于官方文檔):

// logger是一個中間件,注意返回值嵌了好幾層函數  // 我們后面來看看為什么這么設計  function logger(store) {    return function(next) {      return function(action) {        console.group(action.type);        console.info('dispatching', action);        let result = next(action);        console.log('next state', store.getState());        console.groupEnd();        return result      }    }  } // 在createStore的時候將applyMiddleware作為第二個參數傳進去  const store = createStore(    reducer,    applyMiddleware(logger)  )

可以看到上述代碼為了支持中間件,createStore支持了第二個參數,這個參數官方稱為enhancer,顧名思義他是一個增強器,用來增強store的能力的。官方對于enhancer的定義如下:

type StoreEnhancer = (next: StoreCreator) => StoreCreator

上面的結構的意思是說enhancer作為一個函數,他接收StoreCreator函數作為參數,同時返回的也必須是一個StoreCreator函數。注意他的返回值也是一個StoreCreator函數,也就是我們把他的返回值拿出來繼續執行應該得到跟之前的createStore一樣的返回結構,也就是說我們之前的createStore返回啥結構,他也必須返回結構,也就是這個store:

{    subscribe,    dispatch,    getState  }

createStore支持enhancer

根據他關于enhancer的定義,我們來改寫下自己的createStore,讓他支持enhancer:

function createStore(reducer, enhancer) {   // 接收第二個參數enhancer    // 先處理enhancer    // 如果enhancer存在并且是函數    // 我們將createStore作為參數傳給他    // 他應該返回一個新的createStore給我    // 我再拿這個新的createStore執行,應該得到一個store    // 直接返回這個store就行    if(enhancer && typeof enhancer === 'function'){      const newCreateStore = enhancer(createStore);      const newStore = newCreateStore(reducer);      return newStore;    }    // 如果沒有enhancer或者enhancer不是函數,直接執行之前的邏輯    // 下面這些代碼都是之前那版    // 省略n行代碼      // .......    const store = {      subscribe,      dispatch,      getState    }    return store;  }

這部分對應的源碼看這里。

applyMiddleware返回值是一個enhancer

前面我們已經有了enhancer的基本結構,applyMiddleware是作為第二個參數傳給createStore的,也就是說他是一個enhancer,準確的說是applyMiddleware的返回值是一個enhancer,因為我們傳給createStore的是他的執行結果applyMiddleware():

function applyMiddleware(middleware) {    // applyMiddleware的返回值應該是一個enhancer    // 按照我們前面說的enhancer的參數是createStore    function enhancer(createStore) {      // enhancer應該返回一個新的createStore      function newCreateStore(reducer) {        // 我們先寫個空的newCreateStore,直接返回createStore的結果        const store = createStore(reducer);        return store      }        return newCreateStore;    }    return enhancer;  }

實現applyMiddleware

上面我們已經有了applyMiddleware的基本結構了,但是功能還沒實現,要實現他的功能,我們必須先搞清楚一個中間件到底有什么功能,還是以前面的logger中間件為例:

function logger(store) {    return function(next) {      return function(action) {        console.group(action.type);        console.info('dispatching', action);        let result = next(action);        console.log('next state', store.getState());        console.groupEnd();        return result      }    }  }

這個中間件運行效果如下:

怎么理解Redux原理

可以看到我們let result = next(action);這行執行之后state改變了,前面我們說了要改變state只能dispatch(action),所以這里的next(action)就是dispatch(action),只是換了一個名字而已。而且注意最后一層返回值return function(action)的結構,他的參數是action,是不是很像dispatch(action),其實他就是一個新的dispatch(action),這個新的dispatch(action)會調用原始的dispatch,并且在調用的前后加上自己的邏輯。所以到這里一個中間件的結構也清楚了:

  1.   一個中間件接收store作為參數,會返回一個函數

  2.   返回的這個函數接收老的dispatch函數作為參數,會返回一個新的函數

  3.   返回的新函數就是新的dispatch函數,這個函數里面可以拿到外面兩層傳進來的store和老dispatch函數

所以說白了,中間件就是加強dispatch的功能,用新的dispatch替換老的dispatch,這不就是個裝飾者模式嗎?其實前面enhancer也是一個裝飾者模式,傳入一個createStore,在createStore執行前后加上些代碼,最后又返回一個增強版的createStore。可見設計模式在這些優秀的框架中還真是廣泛存在,如果你對裝飾者模式還不太熟悉,可以看我之前這篇文章。

遵循這個思路,我們的applyMiddleware就可以寫出來了:

// 直接把前面的結構拿過來  function applyMiddleware(middleware) {    function enhancer(createStore) {      function newCreateStore(reducer) {        const store = createStore(reducer);         // 將middleware拿過來執行下,傳入store        // 得到第一層函數        const func = middleware(store);            // 解構出原始的dispatch        const { dispatch } = store;             // 將原始的dispatch函數傳給func執行        // 得到增強版的dispatch        const newDispatch = func(dispatch);             // 返回的時候用增強版的newDispatch替換原始的dispatch        return {...store, dispatch: newDispatch}      }         return newCreateStore;    }    return enhancer;  }

照例用我們自己的applyMiddleware替換老的,跑起來是一樣的效果,說明我們寫的沒問題,哈哈~

怎么理解Redux原理

支持多個middleware

我們的applyMiddleware還差一個功能,就是支持多個middleware,比如像這樣:

applyMiddleware(    rafScheduler,    timeoutScheduler,    thunk,    vanillaPromise,    readyStatePromise,    logger,    crashReporter  )

其實要支持這個也簡單,我們返回的newDispatch里面依次的將傳入的middleware拿出來執行就行,多個函數的串行執行可以使用輔助函數compose,這個函數定義如下。只是需要注意的是我們這里的compose不能把方法拿來執行就完了,應該返回一個包裹了所有方法的方法。

function compose(...func){    return funcs.reduce((a, b) => (...args) => a(b(...args)));  }

這個compose可能比較讓人困惑,我這里還是講解下,比如我們有三個函數,這三個函數都是我們前面接收dispatch返回新dispatch的方法:

const fun1 = dispatch => newDispatch2;  const fun2 = dispatch => newDispatch3;  const fun3 = dispatch => newDispatch4;

當我們使用了compose(fun1, fun2, fun3)后執行順序是什么樣的呢?

// 第一次其實執行的是  (func1, func2) => (...args) => func1(fun2(...args))  // 這次執行完的返回值是下面這個,用個變量存起來吧  const temp = (...args) => func1(fun2(...args))  // 我們下次再循環的時候其實執行的是  (temp, func3) => (...args) => temp(func3(...args));  // 這個返回值是下面這個,也就是最終的返回值,其實就是從func3開始從右往左執行完了所有函數  // 前面的返回值會作為后面參數  (...args) => temp(func3(...args));  // 再看看上面這個方法,如果把dispatch作為參數傳進去會是什么效果  (dispatch) => temp(func3(dispatch)); // 然后func3(dispatch)返回的是newDispatch4,這個又傳給了temp(newDispatch4),也就是下面這個會執行  (newDispatch4) => func1(fun2(newDispatch4))  // 上面這個里面用newDispatch4執行fun2(newDispatch4)會得到newDispatch3  // 然后func1(newDispatch3)會得到newDispatch2  // 注意這時候的newDispatch2其實已經包含了newDispatch4和newDispatch3的邏輯了,將它拿出來執行這三個方法就都執行了

更多關于compose原理的細節可以看我之前這篇文章。

所以我們支持多個middleware的代碼就是這樣:

// 參數支持多個中間件  function applyMiddleware(...middlewares) {    function enhancer(createStore) {      function newCreateStore(reducer) {        const store = createStore(reducer);            // 多個middleware,先解構出dispatch => newDispatch的結構        const chain = middlewares.map(middleware => middleware(store));       const { dispatch } = store;              // 用compose得到一個組合了所有newDispatch的函數        const newDispatchGen = compose(...chain);        // 執行這個函數得到newDispatch        const newDispatch = newDispatchGen(dispatch);        return {...store, dispatch: newDispatch}      }         return newCreateStore;    }    return enhancer;  }

最后我們再加一個logger2中間件實現效果:

function logger2(store) {    return function(next) {      return function(action) {        let result = next(action);        console.log('logger2');        return result      }    }  } let store = createStore(reducer, applyMiddleware(logger, logger2));

可以看到logger2也已經打印出來了,大功告成。

怎么理解Redux原理

現在我們也可以知道他的中間件為什么要包裹幾層函數了:

第一層:目的是傳入store參數

第二層:第二層的結構是dispatch => newDispatch,多個中間件的這層函數可以compose起來,形成一個大的dispatch => newDispatch

第三層:這層就是最終的返回值了,其實就是newDispatch,是增強過的dispatch,是中間件的真正邏輯所在。

到此,關于“怎么理解Redux原理”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

长汀县| 明光市| 平陆县| 增城市| 闸北区| 乌鲁木齐县| 乐东| 西畴县| 屏南县| 三江| 武鸣县| 阿拉善盟| 安乡县| 阿拉尔市| 屯门区| 武安市| 鄂托克旗| 永定县| 龙海市| 吉安市| 古丈县| 北碚区| 菏泽市| 万安县| 黎城县| 那曲县| 万州区| 安平县| 南郑县| 汨罗市| 西盟| 普格县| 扎赉特旗| 剑川县| 新蔡县| 武川县| 禹州市| 志丹县| 柏乡县| 安庆市| 抚州市|