最近 Code Review 代碼迎变,發(fā)現(xiàn)幾個項目中可能遇到的問題贯城,可以進(jìn)行的優(yōu)化玩敏。
以下部分借鑒同事的總結(jié)(PS:問題代碼是我的例子)
先從一個需求說起沿侈,某個頁面中有個 Switch 開關(guān)闯第,開關(guān)的狀態(tài)是從后端接口獲取的并保存在 Redux 中,如果點擊這個開關(guān)缀拭,需要切換其狀態(tài)并向后端發(fā)送一個請求咳短。
現(xiàn)有邏輯為:
頁面初始化時從后端接口獲取狀態(tài)并保存在 Redux 中(假設(shè)為 checked 字段),然后通過 props 將傳到 Switch 組件所在的頁面
該頁面接收到 props 時蛛淋,將 checked 這個 props 保存在頁面的 state 中咙好,然后 Switch 組件使用頁面的 state 中的值
點擊 Switch 開關(guān)時修改頁面 state 中的 checked 值,然后再觸發(fā) Redux 中的一個 action (已使用 redux-thunk 處理異步邏輯)去請求后端接口
這樣就會出現(xiàn)一個問題褐荷,如果接口請求失敗勾效,但是頁面顯示的開關(guān)狀態(tài)已經(jīng)切換,導(dǎo)致 UI 顯示與實際狀態(tài)不一致,并且如果其他頁面用到這個狀態(tài)层宫,可能會導(dǎo)致一些意料之外的問題绘迁。
錯誤代碼示范:
<Switch
onChange={(checked)=> (
this.setState({ salesStatus = !checked}),
this.switchSales )}
checked={salesStatus}
style={{ marginLeft: 16 }}
disabled={!quickpay.edit}
/>
正確的操作應(yīng)該為:
<Switch
onChange={this.switchSales}
checked={salesStatus}
loading={XXXXX}
style={{ marginLeft: 16 }}
disabled={!quickpay.edit}
/>
頁面初始化時從后端接口獲取狀態(tài)并保存在 Redux 中(假設(shè)為 checked),并將狀態(tài)通過 props 傳遞到 Switch 開關(guān)組件中卒密,中間不做任何處理
點擊 Switch 開關(guān)時缀台,給其一個 loading 狀態(tài),同時觸發(fā) Redux 中的一個 action 去請求后端接口哮奇,請求完成后根據(jù)請求結(jié)果決定是否修改 Redux 中的 checked 值膛腐,并取消 loading 狀態(tài)
一個很簡單的需求涉及到兩個 React 架構(gòu)中的理念:單一數(shù)據(jù)源和單項數(shù)據(jù)流。
單一數(shù)據(jù)源
單一數(shù)據(jù)源即任何一個狀態(tài)只保存一份鼎俘,例如上述需求中的 checked 狀態(tài)僅保存在 Redux 中即可哲身,不要在某個頁面或組件中重新保存一份這個狀態(tài)值。
注意贸伐,根據(jù)需求偶爾也會有特殊情況勘天,例如 Ant Design Form 中通過 getFieldDecorator 包裝的組件可能需要對傳入 value 進(jìn)行處理后再使用。
單向數(shù)據(jù)流
React 中的數(shù)據(jù)流均為單向的捉邢,父組件通過 props 向子組件傳遞數(shù)據(jù)脯丝,props 發(fā)生改變后,組件會自動重新渲染伏伐。并且一個組件不能修改他的 props 值宠进。
如上述需求中的 checked 狀態(tài),通過 props 從頂層一層一層向下傳遞藐翎,而要修改他的時候材蹬,必須顯式地觸發(fā)一個 action 去修改他。