<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          推薦使用并手寫實(shí)現(xiàn)redux-actions原理

          共 10882字,需瀏覽 22分鐘

           ·

          2020-12-20 22:28

          • 一、前言

          • 二、介紹

            • 2.1 創(chuàng)建action

            • 2.2 reducer

            • 2.3 觸發(fā)action

          • 三、 認(rèn)識(shí)與手寫createAction()

            • 3.1 用法

            • 3.2 原理實(shí)現(xiàn)

          • 四、認(rèn)識(shí)handleActions

          • 五、認(rèn)識(shí)與手寫實(shí)現(xiàn)handleAction

            • 5.1 用法

            • 5.2 原理實(shí)現(xiàn)

          • 六、handleActions原理實(shí)現(xiàn)

          • 最后

          • 參考文章


          一、前言

          為什么介紹redux-actions呢?

          第一次見到主要是接手公司原有的項(xiàng)目,發(fā)現(xiàn)有之前的大佬在處理redux的時(shí)候引入了它。

          發(fā)現(xiàn)也確實(shí) 使得 在對(duì)redux的處理上方便了許多,而我為了更好地使用一個(gè)組件或者插件,都會(huì)去去嘗試閱讀源碼并寫成文章 ,這個(gè)也不例外。

          發(fā)現(xiàn)也確實(shí)有意思,推薦大家使用redux的時(shí)候也引入redux-actions

          在這里就介紹一下其使用方式,并且自己手寫實(shí)現(xiàn)一個(gè)簡單的redux-actions

          二、介紹

          在學(xué)習(xí) redux 中,總覺得 action 和 reducer 的代碼過于呆板,比如

          2.1 創(chuàng)建action

          let?increment?=?()=>({type:"increment"})

          2.2 reducer

          let?reducer?=?(state,action)=>{
          ????switch(action.type){
          ??????case?"increment":return?{count:state.count+1};break;
          ??????case?"decrement":return?{count:state.count-1};break;
          ??????default:return?state;
          ????}
          }

          2.3 觸發(fā)action

          dispatch(increment())

          綜上所示,我們難免會(huì)覺得 increment 和 reducer 做一個(gè)小 demo 還行,遇到邏輯偏復(fù)雜的項(xiàng)目后,項(xiàng)目管理維護(hù)就呈現(xiàn)弊端了。所以最后的方式就是將它們獨(dú)立出來,同時(shí)在 reducer 中給與開發(fā)者更多的主動(dòng)權(quán),不能僅停留在數(shù)字的增增減減。

          redux-actions主要函數(shù)有createAction、createActions、handleAction、handleActions、combineActions。

          基本上就是只有用到createActionhandleActionshandleAction

          所以這里我們就只討論這三個(gè)個(gè)。

          三、 認(rèn)識(shí)與手寫createAction()

          3.1 用法

          一般創(chuàng)建Action方式:

          let?increment?=?()=>({type:"increment"})
          let?incrementObj?=?increment();//?{?type:"increment"}

          使用createAction 創(chuàng)建 action

          import?{?createAction?}?from?'redux-actions';
          const?increment?=?createAction('increment');
          let?incrementObj?=?increment();//?{?type:"increment"}
          let?objincrement?=?increment(10);//?{type:"increment",paylaod:10}

          我們可以看到

          let?increment?=?()=>({type:"increment"})
          let?incrementObj?=?increment();//?{?type:"increment"}

          const?increment?=?createAction('increment');
          let?incrementObj?=?increment();//?{?type:"increment"}

          是等效的,那為什么不直接用傳統(tǒng)方式呢?

          不難發(fā)現(xiàn)有兩點(diǎn):

          1. 傳統(tǒng)方式,需要自己寫個(gè)函數(shù)來返回incrementObj,而利用封裝好的createAtion就不用自己寫函數(shù)
          2. 傳統(tǒng)方式,在返回的incrementObj若是有payload需要自己添加上去,這是多么麻煩的事情啊,你看下面的代碼,如此的不方便。但是用了createAction返回的increment,我們添加上payload,十分簡單,直接傳個(gè)參數(shù),它就直接把它作為payload的值了。
          let?increment?=?()=>({type:"increment",payload:123})

          3.2 原理實(shí)現(xiàn)

          我們先實(shí)現(xiàn)個(gè)簡單,值傳入 type參數(shù)的,也就是實(shí)現(xiàn)下面這段代碼的功能

          const?increment?=?createAction('increment');
          let?incrementObj?=?increment();//?{?type:"increment"}

          我們發(fā)現(xiàn)createAction('increment')()才返回最終的action對(duì)象。這不就是個(gè)柯里化函數(shù)嗎?

          所以我們可以非常簡單的寫出來,如下面代碼所示,我們把type類型當(dāng)作action對(duì)象的一個(gè)屬性了

          function?createAction(type)?{
          ????return?()?=>?{
          ????????const?action?=?{
          ????????????type
          ????????};
          ????????return?action;
          ????};
          }

          好了現(xiàn)在,現(xiàn)在實(shí)現(xiàn)下面這個(gè)功能,也就是有payload的情況

          const?increment?=?createAction('increment');
          let?objincrement?=?increment(10);//?{type:"increment",paylaod:10}

          很明顯,這個(gè)payload是 在createAction('increment')返回的函數(shù)的參數(shù),所以我們輕而易舉地給action添加上了payload。

          function?createAction(type)?{
          ????return?(payload)?=>?{
          ????????const?action?=?{
          ????????????type,
          ????????????payload
          ????????};
          ????????return?action;
          ????};
          }

          但是像第一種情況我們是不傳payload的,也就是說返回的action是不希望帶有payload的,但是這里我們寫成這樣就是 默認(rèn)一定要傳入payload的了。

          所以我們需要添加個(gè)判斷,當(dāng)不傳payload的時(shí)候,action就不添加payload屬性。

          function?createAction(type)?{
          ????return?(payload)?=>?{
          ????????const?action?=?{
          ????????????type,
          ????????};
          ????????if(payload?!==?undefined){
          ????????????action.payload?=?payload
          ????????}
          ????????return?action;
          ????};
          }

          在實(shí)際項(xiàng)目中我更喜歡下面這種寫法,但它是等價(jià)于上面這種寫法的

          function?createAction(type)?{
          ????return?(payload)?=>?{
          ????????const?action?=?{
          ????????????type,
          ????????????...payload?{payload}:{}
          ????????};
          ????????return?action;
          ????};
          }

          其實(shí)createAction的參數(shù)除了type,還可以傳入一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)表示對(duì)payload的處理。

          const?increment?=?createAction('increment');
          let?objincrement?=?increment(10);//?{type:"increment",paylaod:10}

          像上面的代碼所示,我們希望的是傳入10之后是返回的action中的payload是我們傳入的2倍數(shù)

          const?increment?=?createAction('increment',(t)=>?t?*?2);
          let?objincrement?=?increment(10);//?{type:"increment",paylaod:20}

          現(xiàn)在,就讓我們實(shí)現(xiàn)一下。

          function?createAction(type,payloadCreator)?{
          ????return?(payload)?=>?{
          ????????const?action?=?{
          ????????????type,
          ????????};
          ????????if(payload?!==?undefined){
          ????????????action.payload?=?payloadCreator(payload)
          ????????}
          ????????return?action;
          ????};
          }

          臥槽,太簡單了吧!但是我們又犯了前邊同樣的錯(cuò)誤,就是我們使用createAction的時(shí)候,不一定會(huì)傳入payloadCreator這個(gè)回調(diào)函數(shù),所以我們還需要判斷下

          function?createAction(type,payloadCreator)?{
          ????return?(payload)?=>?{
          ????????const?action?=?{
          ????????????type,
          ????????};
          ????????if(payload?!==?undefined){
          ????????????action.payload?=?payloadCreator?payloadCreator(payload):payload
          ????????}
          ????????return?action;
          ????};
          }

          臥槽,完美。

          接下來看看 redux-action的 handleActions吧

          四、認(rèn)識(shí)handleActions

          我們先看看傳統(tǒng)的reducer是怎么使用的

          let?reducer?=?(state,action)=>{
          ????switch(action.type){
          ??????case?"increment":return?{count:state.count+1};break;
          ??????case?"decrement":return?{count:state.count-1};break;
          ??????default:return?state;
          ????}
          }

          再看看使用了handleActions

          const?INCREMENT?=?"increment"
          const?DECREMENT?=?"decrement"
          var?reducer?=?handleActions({
          ????[INCREMENT]:?(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ????}),
          ????[DECREMENT]:?(state,?action)?=>?({
          ??????counter:?state.counter?-?action.payload
          ????})
          },initstate)

          這里大家不要被{[DECREMENT]:(){}} 的寫法嚇住哈,就是把屬性寫成變量了而已。

          我們?cè)诳刂婆_(tái) console.log(reducer) 看下結(jié)果

          最后返回的就是一個(gè) reducer 函數(shù)。

          這樣就實(shí)現(xiàn)了 reducer 中功能化的自由,想寫什么程序,我們只要寫在

          {[increment]:(state,action)=>{}}?

          這個(gè)函數(shù)內(nèi)就行,同時(shí)也可以把這些函數(shù)獨(dú)立成一個(gè)文件,再引入進(jìn)來就行

          import?{increment,decrement}from?"./reducers.js"
          var?initstate?=?{count:0}
          var?reducer?=?createReducer({
          ????[INCREMENT]:?increment,
          ????[DECREMENT]:?decrement
          },initstate)

          reducers.js

          //reducers.js
          export?let?increment?=?(state,action)=>({counter:?state.counter?+?action.payload})
          export?let?decrement?=?(state,action)=>({counter:?state.counter?-?action.payload})

          可見,

          handleactions 可以簡化 reducers 的寫法 不用那么多 switch 而且可以把函數(shù)獨(dú)立出來,這樣reducer就再也不會(huì)有一大堆代碼了。

          本來要講handleActions的實(shí)現(xiàn)了,但是在這之前,我們必須先講一下handleAction,對(duì),你仔細(xì)看,沒有s

          五、認(rèn)識(shí)與手寫實(shí)現(xiàn)handleAction

          5.1 用法

          看下使用方式

          const?incrementReducer?=?handleAction(INCREMENT,?(state,?action)?=>?{
          ??return?{counter:?state.counter?+?action.payload}
          },?initialState);

          可以看出來,跟handleActions的區(qū)別 就是,handleAction生成的reducer是專門來處理一個(gè)action的。

          5.2 原理實(shí)現(xiàn)

          如果你看過redux原理的話(如果你沒看過的話,推薦你去看下我之前的文章Redux 源碼解析系列(一) -- Redux的實(shí)現(xiàn)思想),相信你應(yīng)該知道reducer(state,action)返回的結(jié)果是一個(gè)新的state,然后這個(gè)新的state會(huì)和舊的state進(jìn)行對(duì)比,如果發(fā)現(xiàn)兩者不一樣的話,就會(huì)重新渲染使用了state的組件,并且把新的state賦值給舊的state.

          也就是說handleAction()返回一個(gè)reducer函數(shù),然后incrementReducer()返回一個(gè)新的state。

          先實(shí)現(xiàn)返回一個(gè)reducer函數(shù)

          function?handleAction(type,?callback)?{
          ????return?(state,?action)?=>?{
          ??????
          ????};
          }

          接下來應(yīng)當(dāng)是執(zhí)行reducer(state,action)是時(shí)候返回state,也就是執(zhí)行下面返回的這個(gè)

          (state,?action)?=>?{
          ??????
          };

          而其實(shí)就是執(zhí)行callback(state) 然后返回一個(gè)新的 state

          function?handleAction(type,?callback)?{
          ????return?(state,?action)?=>?{
          ????????
          ??????return?callback(state)
          ????};
          }

          或許你會(huì)有疑問,為什么要這么搞,而不直接像下面這樣,就少了一層包含。

          function?handleAction(state,type,?callback)?{
          ????return?callback(state)
          }

          這才是它的巧妙之處。它在handleAction()返回的reducer()時(shí),可不一定會(huì)執(zhí)行callback(state),只有handleAction傳入的type跟reducer()中傳入的action.type匹配到了才會(huì)執(zhí)行,否則就直接return state。表示沒有任何處理

          function?handleAction(type,?callback)?{
          ????return?(state,?action)?=>?{
          ????????
          ??????return?callback(state)
          ????};
          }

          因此我們需要多加一層判斷

          function?handleAction(type,?callback)?{
          ????return?(state,?action)?=>?{
          ????????if?(action.type?!==?type)?{
          ????????????return?state;
          ????????}
          ????????return?callback(state)
          ????};
          }

          多么完美啊!

          好了現(xiàn)在我們來實(shí)現(xiàn)下handleActions

          六、handleActions原理實(shí)現(xiàn)

          function?handleActions(handlers,?defaultState)?{
          ????const?reducers?=?Object.keys(handlers).map(type?=>?{
          ????????return?handleAction(type,?handlers[type]);
          ????});
          ????const?reducer?=?reduceReducers(...reducers)
          ????return?(state?=?defaultState,?action)?=>?reducer(state,?action)
          }

          看,就這幾行代碼,是不是很簡單,不過應(yīng)該不好理解,不過沒關(guān)系,我依舊將它講得粗俗易懂。

          我們拿上面用到的例子來講好了

          var?reducer?=?handleActions({
          ????[INCREMENT]:?(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ????}),
          ????[DECREMENT]:?(state,?action)?=>?({
          ??????counter:?state.counter?-?action.payload
          ????})
          },initstate)
          {
          ????[INCREMENT]:?(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ????}),
          ????[DECREMENT]:?(state,?action)?=>?({
          ??????counter:?state.counter?-?action.payload
          ????})

          上面這個(gè)對(duì)象,經(jīng)過下面的代碼之后

          const?reducers?=?Object.keys(handlers).map(type?=>?{
          ????????return?handleAction(type,?handlers[type]);
          ????});

          返回的reducer,其實(shí)就是

          [
          ??handleAction(INCREMENT,(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ??})),
          ??handleAction(DECREMENT,(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ??})),
          ]

          為什么要變成一個(gè)handleAction的數(shù)組,

          我大概想到了,是想每次dispatch(action)的時(shí)候,就要遍歷去執(zhí)行這個(gè)數(shù)組中的所有handleAction。

          那豈不是每個(gè)handleAction返回的reducer都要執(zhí)行?確實(shí),但是別忘了我們上面講到的,如果handleAction 判斷到 type和action.type 是不會(huì)對(duì)state進(jìn)行處理的而是直接返回state

          function?handleAction(type,?callback)?{
          ????return?(state,?action)?=>?{
          ????????if?(action.type?!==?type)?{
          ????????????return?state;
          ????????}
          ????????return?callback(state)
          ????};
          }

          沒有即使每個(gè) handleAction 都執(zhí)行了也沒關(guān)系

          那應(yīng)該怎么遍歷執(zhí)行,用map,forEach?不,都不對(duì)。我們看回源碼

          function?handleActions(handlers,?defaultState)?{
          ????const?reducers?=?Object.keys(handlers).map(type?=>?{
          ????????return?handleAction(type,?handlers[type]);
          ????});
          ????const?reducer?=?reduceReducers(...reducers)
          ????return?(state?=?defaultState,?action)?=>?reducer(state,?action)
          }

          使用了

          const?reducer?=?reduceReducers(...reducers)

          用了reduceReducers這個(gè)方法,顧名思義,看這方法名,意思就是用reduce這個(gè)來遍歷執(zhí)行reducers這個(gè)數(shù)組。也就是這個(gè)數(shù)組。

          [
          ??handleAction(INCREMENT,(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ??})),
          ??handleAction(DECREMENT,(state,?action)?=>?({
          ??????counter:?state.counter?+?action.payload
          ??})),
          ]

          我們看下reduceReducers的內(nèi)部原理

          function?reduceReducers(...args)?{
          ????const?reducers?=?args;
          ????return?(prevState,?value)?=>?{
          ????????return?reducers.reduce((newState,?reducer,?index)?=>?{
          ????????????return?reducer(newState,?value);
          ????????},?prevState);
          ????};
          };

          我們發(fā)現(xiàn)將reducers這個(gè)數(shù)組放入reduceReducers,然后執(zhí)行reduceReducers,就會(huì)返回

          (prevState,?value)?=>?{
          ????return?reducers.reduce((newState,?reducer,?index)?=>?{
          ????????return?reducer(newState,?value);
          ????},?prevState);
          };

          這個(gè)方法,也就是說執(zhí)行這個(gè)方法就會(huì) 執(zhí)行

          return?reducers.reduce((newState,?reducer,?index)?=>?{
          ????????return?reducer(newState,?value);
          ????},?prevState);

          也就是會(huì)使用reduce遍歷執(zhí)行reducers,為什么要用reduce來遍歷呢?

          這是因?yàn)樾枰焉弦粋€(gè)handleAction執(zhí)行后返回的state傳遞給下一個(gè)。

          這個(gè)思想有一點(diǎn)我們之間之前講的關(guān)于compose函數(shù)的思想,感興趣的話,可以去看一下【前端進(jìn)階之認(rèn)識(shí)與手寫compose方法】

          function?handleActions(handlers,?defaultState)?{
          ????const?reducers?=?Object.keys(handlers).map(type?=>?{
          ????????return?handleAction(type,?handlers[type]);
          ????});
          ????const?reducer?=?reduceReducers(...reducers)
          ????return?(state?=?defaultState,?action)?=>?reducer(state,?action)
          }

          現(xiàn)在也就是說這里的reducer是reduceReducers(...reducers)返回的結(jié)果,也就

          reducer?=?(prevState,?value)?=>?{
          ????return?reducers.reduce((newState,?reducer,?index)?=>?{
          ????????return?reducer(newState,?value);
          ????},?prevState);
          };

          而handleActions返回

          (state?=?defaultState,?action)?=>?reducer(state,?action)

          也就是說handleActions其實(shí)是返回這樣一個(gè)方法。

          (state?=?defaultState,?action)?=>?{
          ????return?reducers.reduce((newState,?reducer,?index)?=>?{
          ????????return?reducer(newState,?value);
          ????},?state);
          }

          好家伙,在handleAction之間利用reduce來傳遞state,真是個(gè)好方法,學(xué)到了。

          貼一下github 的redux-action的源碼地址,感興趣的朋友可以親自去閱讀一下,畢竟本文是做了簡化的 redux-actions:https://github.com/redux-utilities/redux-actions

          最后

          文章首發(fā)于公眾號(hào)《前端陽光》,歡迎加入技術(shù)交流群。

          參考文章

          —————END—————



          喜歡本文的朋友,歡迎關(guān)注公眾號(hào)?前端陽光,收看更多精彩內(nèi)容

          點(diǎn)個(gè)[在看],是對(duì)我最大的支持!


          如果覺得這篇文章還不錯(cuò),來個(gè)【分享、點(diǎn)贊、在看】三連吧,讓更多的人也看到~


          瀏覽 53
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜久久 | 大香蕉97超碰 | 亚洲天堂直播 | 豆花视频免费 | 男女激情网站 |