在Redux中,應該把邏輯放在action creator里,還是分散在reducer里?
例如用戶點擊按鈕,需要修改state樹的兩個部分。例如點擊保存按鈕,需要更新頁面數據,同時關閉彈窗。
是應該:
1. 在action creator里dispatch兩個action:UPDATE_XXX_DATA和CLOSE_EDIT_MODAL
還是:
2. dispatch一個action:EDIT_MODAL_SAVE_CLICKED,然後在對應的兩個reducer里都接收這個action;
第一種方式可能全局只需要較少的action type,由action creator去組合使用,而第二種需要較多的action type(因為有很多種組合的情況)。
我覺得第二種方式action的語義更清楚,但是好像把業務邏輯寫到reducer里不是很合適?
首先討論這個問題必須達成的幾點共識:
1.action到reduce到nextState是同步代碼,因此在action和reducer都可以傳遞state的變化。
2.存在業務場景,一個行為會觸發多個handler,比如button click要觸發ajax和UI close。然後再討論問題的解法:
1. observable模式。讓一個action觸發一系列observable事件,每一個事件action in, action out,從而觸發多次state update。比如我現在常用的redux-observable,這個的好處是邏輯清晰,不用把不想乾的兩件事情放到一個action。2. merge actions。寫redux要學會設計UI的最小數據映射關係。這個的意思是頁面關閉是否和保存動作強相關,如果是,則沒有action的必要。總結,兩個建議:1. 用observable來分發action的依賴關係,盡量讓UI更新這件事和保存這件事分開來處理。
2.思考下這個問題是否存在,有沒有可能讓store設計的更簡單點。如果沒有更好的辦法,則通常會採用在一個action來描述這件事情,在reducer裡面做分發。【not recommended】如果是 state 樹的兩個部分,那麼在 action creator 里分別 dispatch 較好
不要從實現細節上去考慮這個問題,盡量從場景上去考慮問題,考慮出發點應該是這個模塊需要暴露什麼樣的「行為」,「行為」就是action,決定action怎麼設計。
通常,應該盡量把邏輯往action creator中推,讓reducer中的邏輯越簡單越好。
特定於這個例子,分開兩個action creator更好,兩個action type,一個UPDATE_XXX_DATA,另一個CLOSE_EDIT_MODAL,因為明顯「更新數據」和「關閉彈窗」是兩個不同的行為。就算現在這兩個「行為」是同時發生的,將來也可能是兩個不同時發生,因為這兩個「行為」真的不相干。
實際上,更新數據的行為可能涉及到AJAX請求,就會有延時才得到是否更新數據成功的結果。好一點的設計,先發出UPDATE_XXX_DATA這個action,得到結果之後,再發出CLOSE_EDIT_MODAL這個action,這樣合理一點。
前面@流形@程墨Morgan老師說得比較清楚了,我就個人使用說個意見。
方案:如果都是同步的,我傾向於第一種方式。但是一旦涉及到非同步,要用到中間件了,可以選擇在react中dispatch一個類似第二種方案里的複雜action(注意這個action是給中間件而不是reducer的),然後在中間件里搞非同步請求和相關處理邏輯,然後拆分成兩個action(類似於方案1里的形式)分別dispatch給reducer。
原因:1.我覺得給reducer處理的每個action都需要比較「通用」,有「原子性」,action是應該和store內容相關而不是和你有什麼業務相關。原因是(1)reducer能感知的只是部分store (2)如果用第二種方案,想像下你要在modal控制相關的reducer里寫多少個業務相關的case,而且你會發現這些case做的事情往往都是相同的,比如把modalVisiable欄位設置成false。p.s. 如果題主覺得我說得亂的話,記住第一種方案是更好的方案就好了。遇到解決不了的問題在它的基礎上想辦法。就我的經驗上來看,是放到action creator里,如果是兩個action就應該分開,而且 reducer里本身就是一堆的switch case里再加if else更難維護
看到一群人說【讓reducer中的邏輯越簡單越好】【很少會在reducer裡面處理業務邏輯】我是一臉懵逼的……
最testable的部分(純函數),不去承擔最複雜的邏輯,最值得test的業務,那要你何用?我要這reducer有何用?
我真的建議每天把redux掛在嘴邊的人多少看看elm,哪怕寫個todomvc demo試試呢……好歹也知道redux哪些地方抄偏了啊
回到樓主的問題上來,在redux中通常會選擇後省,即兩個action,在action creator中還是在組件上通過chainable action做看具體場景和對action的抽象
但是! 這是不得已而為之的——因為在redux中沒有更好的辦法,這裡是redux的缺陷,不是理所當然的
原因在於elm的update 函數可以繼續產生副作用和新的action,而redux不行(目前redux生態里最接近elm結構的是redux-loop,不想看elm的也可以看看它大概理解下)。
在elm里是沒有 action creator、middleware、mapStateToProps、normalize這些東西的,那麼問題來了:elm是怎麼處理這個問題的?
==========分割線===========
有人說,為什麼你老是提elm,老是想往elm上靠。
好問題。
首先,redux官方任何只要不涉及side effect的example,全都是elm的路子,比如counter-list,但是真到項目里,有幾個人像example這樣,用redux管理組件狀態,讓他們可組合?
沒有,問題出在哪?真實的項目必然有非同步,而非同步依賴的middleware機制,就是現在阻礙redux分形的最大障礙。
middleware機制有問題不是我說的,這點Dan自己承認(出處見後)
This is the big problem with middleware. When you compose independent apps into a single app, neither of them is 「at the top」. This is where the today』s Redux paradigm breaks down—we don』t have a good way of composing side effects of independent 「subapplications」.
實際項目中分形被阻礙,進一步導致了redux社區的抽象也和elm完全不一樣——問題是一環套一環的。
解決方向是什麼?還是用Dan自己的話來說吧,免得有人老覺得是我鑽elm的牛角尖:
However, this problem has been solved before! If we had a fractal solution like Elm Architecture for side effects, this would not be an issue.
所以啊,一直想讓redux往elm上靠的不是我,是Dan啊親們,這鍋我背不起啊
當然middleware機制的問題不全是設計問題,也和js語言有關,Dan也一直在留意js語言的進化,試圖早點把elm architechture帶進redux:
I think that what @sebmarkbage suggested in this Algebraic Effects proposal is exactly what would solve this problem for us.
If reducers could 「throw」 effects to the handlers up the stack (in this case, Redux store) and then continue from they left off, we would be able to implement Elm Architecture a la Redux Loop without the awkwardness.
以上所有引用,全部出自Dan自己開的issue:Reducer Composition with Effects in JavaScript · Issue #1528 · reactjs/redux
邏輯處理放在action裡面,reducer應該盡量保證簡單。action裡面可以進行數據處理等side effect,且劃分出合理的粒度也能個保證action的復用。
從語意上,邏輯應該放在reducer里,action只是一個動作信號。但實際上,隨著業務越來越複雜,很容易發現,在fat action才是比較合適的,它有以下幾個優點:1.配合redux-thunk,能處理非同步的事情2.有獲取整個state的能力,如果你的action需要其他節點的數據
3.能dispath多個其它的action
再但是,也不要拘泥說,完全的fat action,所有的reducer只能用payload覆蓋當前的值。只是說,可以把比較複雜的邏輯放在action里,讓reduer處理一些比較簡單的邏輯,不然很有可能,你會把一件簡單的事情做複雜。比如:count+1,放action里要比放reducer里多一步「找到count」的事情。最後,可以使用redux-action,讓發出action,處理reduer時,代碼可讀性更高,更容易維護。actionCreator 更好。副作用反正你要集中處理,盡量讓 reducer 的測試不要太多上下文的東西。
大家探討下啊…我也是新人(?????)
什麼樣的邏輯,要考慮放的位置?我的做法,目前是…
和redux的state相關的放在redux層和react的props相關的放在react層
和state轉換propa相關的放在connect層react層格式化數據成action需要的
中間層通過數據獲取數據,格式化成reducer需要的reducer把數據(增刪改)到state里,返回新stateconnect層把redux的state轉化成propsreact層獲得數據刷新組件action creator 只是簡單的格式生成器,並不內含邏輯
————————————————
另外,樓主的一個action觸發多個action的情況?( ˙ ? ˙ )?我目前用中間件解決……
因為,我認為,1.react層觸發的redux事件,應該是簡單的…2.reducer只負責更新自身狀態,邏輯應該也是簡單的…所以…只能在數據到達reducer之前搞事情了(?≧?≦?)首先 第二種說法是存在一定問題的 如果你只使用了一個redux 那麼 全局只有一個大reducer,也就是action type不能重複; 當然還有解決辦法,就是自己寫redux middleware,在合適的是個dispatch另一個action; 這時候你會發現這裡也是兩個action,對應兩個狀態改變,reducer的兩個部分。
這裡默認了state有兩部分,一個控制是UI狀態,一個控制數據狀態,也就是@流形大大說的狀態的兩部分,這樣分兩個action會比較合適。
弄清了上面的情況以後,相對合理的做法當然是組合兩個action,也就是你在action creator中dispatch這兩個action,或者在saga的effect中put兩個action。
我比較喜歡後者,先撇開測試不談,用一個effect來發出兩個action,然後使用的時候,你就可以當成發一個action,實際上是effect啦,比action creator清晰一點,redux dev tools也有記錄。如果需要多加只是關閉彈窗這種簡單操作。因為我們項目的這種狀態一般是放在local state裡面的。所以一般會讓第一個action creater返回promise。在ui層setstate
我之前也思考過這個問題,我的答案是業務邏輯放action里,理由很簡單,acton能訪問整個store,如果放reducer里,需要訪問另外一個reducer姐的數據基本上做不到!
一般來說的話,很少會在reducer裡面處理業務邏輯,action一般就是把它當作對數據操作的手段,類似於對資料庫的增刪改查,業務邏輯一般在action creator裡面做。
但是對於第一種情況同時dispatch兩個action存在一個問題,就是如果這次update操作是一個非同步操作的話,需要考慮更新失敗後該如何處理。所以這裡不應該直接dispatch兩個action。可以依賴redux-thunk類似的中間件,拆成兩個action creator,updateActionCreator和modalTriggerActionCreator。dispatch updateActionCreator後,根據返回狀態在updateActionCreator裡面處理Modal的狀態。
其實這種場景蠻適合redux-observable的,把邏輯都放到Epics裡面去做處理。
萌新講講自己的看法,
感覺應該在action里處理邏輯啊。
很簡單,現在這個動作你是需要更新某些頁面了,那如果之後某個動作只需要更新其中部分呢?你難道還要再寫一個action么?那麼多組件那麼多排列組合你都要寫成action么?
所以個人觀點:一個action應該對應一個組件更新事件,至於一個動作觸發多個組件更新。那就是在action creator裡面添加邏輯,dispatch多個action。
可能特殊需求會有特殊的處理吧。
我的做法是分開兩個action creator,比如點擊按鈕之後先更新數據dispatch一個action,reducer去更新數據,再dispatch一個action,reducer去關閉彈窗,盡量粒度細一點,如果之後有其他業務邏輯需要單獨dispatch更新數據的action或者關閉彈窗的action的話這樣會更方便調用
講道理的話你這兩種方式其實都算同一種,都是把兩個操作合併到一起,要麼合併action指令要麼合併reducer更新數據操作,如果其他業務邏輯只需要更新數據是不是還得再寫一個action creator專門負責更新數據
不請自來,最近也在糾結這個問題,我們項目目前是處理邏輯都放在reducer中,action只是相當於一個指令,所以也在糾結這個問題......
action里。只不過有些action可以抽象一個方法,配置一個常量統一管理。個人只會reducer處理數據,action里處理邏輯。不知道大家怎麼用的
建議用Vuex
推薦閱讀:
※如何評價微軟開源的ReactXP?
※如何評價 Facebook開源的 YOGA?
※網上都說操作真實 DOM 慢,但測試結果卻比 React 更快,為什麼?
※2017 年底如何比較 Angular 4, React 16, Vue 2 的開發和運行速度?
※如何理解 Vue.JS 2016年的 github 星標( Star )數量增長超過 React ?
TAG:JavaScript | React | Redux |