溫馨提示×

溫馨提示×

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

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

怎么理解和掌握Redux

發(fā)布時間:2021-11-05 11:55:35 來源:億速云 閱讀:137 作者:iii 欄目:web開發(fā)

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

一、Why Redux

在說為什么用 Redux 之前,讓我們先聊聊組件通信有哪些方式。常見的組件通信方式有以下幾種:

  • 父子組件:props、state/callback回調(diào)來進行通信

  • 單頁面應用:路由傳值

  • 全局事件比如EventEmitter監(jiān)聽回調(diào)傳值

  • react中跨層級組件數(shù)據(jù)傳遞Context(上下文)

在小型、不太復雜的應用中,一般用以上幾種組件通信方式基本就足夠了。

但隨著應用逐漸復雜,數(shù)據(jù)狀態(tài)過多(比如服務端響應數(shù)據(jù)、瀏覽器緩存數(shù)據(jù)、UI狀態(tài)值等)以及狀態(tài)可能會經(jīng)常發(fā)生變化的情況下,使用以上組件通信方式會很復雜、繁瑣以及很難定位、調(diào)試相關問題。

因此狀態(tài)管理框架(如 Vuex、MobX、Redux等)就顯得十分必要了,而 Redux 就是其中使用最廣、生態(tài)最完善的。

二、Redux Data flow

在一個使用了 Redux 的 App應用里面會遵循下面四步:

第一步:通過store.dispatch(action)來觸發(fā)一個action,action就是一個描述將要發(fā)生什么的對象。如下:

bindActionCreator就是將發(fā)送actions的過程簡化,當調(diào)用這個返回的函數(shù)時就自動調(diào)用dispatch,發(fā)送對應的action。

bindActionCreators根據(jù)不同類型的actionCreators做不同的處理,actionCreators是函數(shù)就返回函數(shù),是對象就返回一個對象。主要是將actions轉化為dispatch(action)格式,方便進行actions的分離,并且使代碼更加簡潔。

5、compose.js

/**
 * Composes single-argument functions from right to left. The rightmost
 * function can take multiple arguments as it provides the signature for
 * the resulting composite function.
 *
 * @param {...Function} funcs The functions to compose.
 * @returns {Function} A function obtained by composing the argument functions
 * from right to left. For example, compose(f, g, h) is identical to doing
 * (...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)))
}

compose是函數(shù)式變成里面非常重要的一個概念,在介紹compose之前,先來認識下什么是 Reduce?官方文檔這么定義reduce:reduce()方法對累加器和數(shù)組中的每個元素(從左到右)應用到一個函數(shù),簡化為某個值。compose是柯里化函數(shù),借助于Reduce來實現(xiàn),將多個函數(shù)合并到一個函數(shù)返回,主要是在middleware中被使用。

6、applyMiddleware.js

/**
 * Creates a store enhancer that applies middleware to the dispatch method
 * of the Redux store. This is handy for a variety of tasks, such as expressing
 * asynchronous actions in a concise manner, or logging every action payload.
 */export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {    const store = createStore(...args)
    ...
    ...    return {
      ...store,
      dispatch
    }
  }
}

applyMiddleware.js文件提供了middleware中間件重要的API,middleware中間件主要用來對store.dispatch進行重寫,來完善和擴展dispatch功能。

那為什么需要中間件呢?

首先得從Reducer說起,之前 Redux三大原則里面提到了reducer必須是純函數(shù),下面給出純函數(shù)的定義:

  • 對于同一參數(shù),返回同一結果

  • 結果完全取決于傳入的參數(shù)

  • 不產(chǎn)生任何副作用

至于為什么reducer必須是純函數(shù),可以從以下幾點說起?

  • 因為 Redux 是一個可預測的狀態(tài)管理器,純函數(shù)更便于 Redux進行調(diào)試,能更方便的跟蹤定位到問題,提高開發(fā)效率。

  • Redux 只通過比較新舊對象的地址來比較兩個對象是否相同,也就是通過淺比較。如果在 Reducer 內(nèi)部直接修改舊的state的屬性值,新舊兩個對象都指向同一個對象,如果還是通過淺比較,則會導致 Redux 認為沒有發(fā)生改變。但要是通過深比較,會十分耗費性能。最佳的辦法是 Redux返回一個新對象,新舊對象通過淺比較,這也是 Reducer是純函數(shù)的重要原因。

Reducer是純函數(shù),但是在應用中還是會需要處理記錄日志/異常、以及異步處理等操作,那該如何解決這些問題呢?

這個問題的答案就是中間件??梢酝ㄟ^中間件增強dispatch的功能,示例(記錄日志和異常)如下:

const store = createStore(reducer);const next = store.dispatch; 
// 重寫store.dispatchstore.dispatch = (action) => {    try {
        console.log('action:', action);
        console.log('current state:', store.getState());
        next(action);
        console.log('next state', store.getState());
    } catch (error){
        console.error('msg:', error);
    }
}

五、從零開始實現(xiàn)一個簡單的Redux

既然是要從零開始實現(xiàn)一個Redux(簡易計數(shù)器),那么在此之前我們先忘記之前提到的store、Reducer、dispatch等各種概念,只需牢記Redux是一個狀態(tài)管理器。

首先我們來看下面的代碼:

let state = {
    count : 1}//修改之前console.log (state.count);//修改count的值為2state.count = 2;//修改之后console.log (state.count);

我們定義了一個有count字段的state對象,同時能輸出修改之前和修改之后的count值。但此時我們會發(fā)現(xiàn)一個問題?就是其它如果引用了count的地方是不知道count已經(jīng)發(fā)生修改的,因此我們需要通過訂閱-發(fā)布模式來監(jiān)聽,并通知到其它引用到count的地方。因此我們進一步優(yōu)化代碼如下:

let state = {
    count: 1};//訂閱function subscribe (listener) {
    listeners.push(listener);
}function changeState(count) {
    state.count = count;    for (let i = 0; i < listeners.length; i++) {        const listener = listeners[i];
        listener();//監(jiān)聽
    }
}

此時我們對count進行修改,所有的listeners都會收到通知,并且能做出相應的處理。但是目前還會存在其它問題?比如說目前state只含有一個count字段,如果要是有多個字段是否處理方式一致。同時還需要考慮到公共代碼需要進一步封裝,接下來我們再進一步優(yōu)化:

const createStore = function (initState) {
    let state = initState;    //訂閱
    function subscribe (listener) {
        listeners.push(listener);
    }    function changeState (count) {
        state.count = count;        for (let i = 0; i < listeners.length; i++) {            const listener = listeners[i];
            listener();//通知
        }
    }    function getState () {
        return state;
    }    return {
        subscribe,
        changeState,
        getState
    }
}

我們可以從代碼看出,最終我們提供了三個API,是不是與之前Redux源碼中的核心入口文件index.js比較類似。但是到這里還沒有實現(xiàn)Redux,我們需要支持添加多個字段到state里面,并且要實現(xiàn)Redux計數(shù)器。

let initState = {
    counter: {
        count : 0
    },
    info: {
        name: '',
        description: ''
    }
}let store = createStore(initState);//輸出countstore.subscribe(()=>{    let state = store.getState();
    console.log(state.counter.count);
});//輸出infostore.subscribe(()=>{    let state = store.getState();
    console.log(`${state.info.name}:${state.info.description}`);
});

通過測試,我們發(fā)現(xiàn)目前已經(jīng)支持了state里面存多個屬性字段,接下來我們把之前changeState改造一下,讓它能支持自增和自減。

//自增store.changeState({
    count: store.getState().count + 1});//自減store.changeState({
    count: store.getState().count - 1});//隨便改成什么store.changeState({
    count: 金融
});

我們發(fā)現(xiàn)可以通過changeState自增、自減或者隨便改,但這其實不是我們所需要的。我們需要對修改count做約束,因為我們在實現(xiàn)一個計數(shù)器,肯定是只希望能進行加減操作的。所以我們接下來對changeState做約束,約定一個plan方法,根據(jù)type來做不同的處理。

function plan (state, action) => {
  switch (action.type) {    case 'INCREMENT':      return {
        ...state,
        count: state.count + 1
      }    case 'DECREMENT':      return {
        ...state,
        count: state.count - 1
      }    default:      return state
  }
}let store = createStore(plan, initState);//自增store.changeState({
    type: 'INCREMENT'});//自減store.changeState({
    type: 'DECREMENT'});

我們在代碼中已經(jīng)對不同type做了不同處理,這個時候我們發(fā)現(xiàn)再也不能隨便對state中的count進行修改了,我們已經(jīng)成功對changeState做了約束。我們把plan方法做為createStore的入?yún)?,在修改state的時候按照plan方法來執(zhí)行。到這里,恭喜大家,我們已經(jīng)用Redux實現(xiàn)了一個簡單計數(shù)器了。

這就實現(xiàn)了 Redux?這怎么和源碼不一樣啊

然后我們再把plan換成reducer,把changeState換成dispatch就會發(fā)現(xiàn),這就是Redux源碼所實現(xiàn)的基礎功能,現(xiàn)在再回過頭看Redux的數(shù)據(jù)流圖是不是更加清晰了。

怎么理解和掌握Redux

六、Redux Devtools

Redux devtools是Redux的調(diào)試工具,可以在Chrome上安裝對應的插件。對于接入了Redux的應用,通過 Redux devtools可以很方便看到每次請求之后所發(fā)生的改變,方便開發(fā)同學知道每次操作后的前因后果,大大提升開發(fā)調(diào)試效率。

怎么理解和掌握Redux

如上圖所示就是 Redux devtools的可視化界面,左邊操作界面就是當前頁面渲染過程中執(zhí)行的action,右側操作界面是State存儲的數(shù)據(jù),從State切換到action面板,可以查看action對應的 Reducer參數(shù)。切換到Diff面板,可以查看前后兩次操作發(fā)生變化的屬性值。

到此,關于“怎么理解和掌握Redux”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

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

AI