溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Redux-actions的原理和使用

發(fā)布時(shí)間:2021-06-21 16:12:01 來(lái)源:億速云 閱讀:142 作者:chen 欄目:web開(kāi)發(fā)

這篇文章主要介紹“Redux-actions的原理和使用”,在日常操作中,相信很多人在Redux-actions的原理和使用問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Redux-actions的原理和使用”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

一、前言

為什么介紹redux-actions呢?

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

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

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

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

二、介紹

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

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

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

基本上就是只有用到createAction,handleActions,handleAction

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

三、 認(rèn)識(shí)與手寫(xiě)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. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 傳統(tǒng)方式,需要自己寫(xiě)個(gè)函數(shù)來(lái)返回incrementObj,而利用封裝好的createAtion就不用自己寫(xiě)函數(shù)

  3. 傳統(tǒng)方式,在返回的incrementObj若是有payload需要自己添加上去,這是多么麻煩的事情啊,你看下面的代碼,如此的不方便。但是用了createAction返回的increment,我們添加上payload,十分簡(jiǎn)單,直接傳個(gè)參數(shù),它就直接把它作為payload的值了。

let increment = ()=>({type:"increment",payload:123})

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

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

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

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

所以我們可以非常簡(jiǎn)單的寫(xiě)出來(lái),如下面代碼所示,我們把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的,也就是說(shuō)返回的action是不希望帶有payload的,但是這里我們寫(xiě)成這樣就是  默認(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)目中我更喜歡下面這種寫(xiě)法,但它是等價(jià)于上面這種寫(xiě)法的

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; };}

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

太簡(jiǎn)單了吧!但是我們又犯了前邊同樣的錯(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;     }; }

完美。

接下來(lái)看看 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]:(){}} 的寫(xiě)法嚇住哈,就是把屬性寫(xiě)成變量了而已。

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

Redux-actions的原理和使用

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

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

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

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

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})

可見(jiàn),

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

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

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

5.1 用法

看下使用方式

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

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

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

如果你看過(guò)redux原理的話(如果你沒(méi)看過(guò)的話,推薦你去看下我之前的文章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.

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

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

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

接下來(lái)應(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ì)有疑問(wèn),為什么要這么搞,而不直接像下面這樣,就少了一層包含。

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

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

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)在我們來(lái)實(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) }

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

我們拿上面用到的例子來(lái)講好了

  1. var reducer = handleActions({ 

  2.     [INCREMENT]: (state, action) => ({ 

  3.       counter: state.counter + action.payload 

  4.     }), 

  5.     [DECREMENT]: (state, action) => ({ 

  6.       counter: state.counter - action.payload 

  7.     }) 

  8. },initstate) 


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

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

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)     }; }

沒(méi)有即使每個(gè) handleAction 都執(zhí)行了也沒(méi)關(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è)來(lái)遍歷執(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è)方法,也就是說(shuō)執(zhí)行這個(gè)方法就會(huì) 執(zhí)行

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

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

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

這個(gè)思想有一點(diǎn)我們之間之前講的關(guān)于compose函數(shù)的思想,感興趣的話,可以去看一下【前端進(jìn)階之認(rèn)識(shí)與手寫(xiě)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)在也就是說(shuō)這里的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)

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

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

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

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

到此,關(guān)于“Redux-actions的原理和使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

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

AI