使用React hooks處理複雜表單狀態數據

使用hooks替換this.setState()
使用hooks替換this.setState()

自從React hooks*發佈以來已經有一段時間了,我很喜歡這個特性。這個hooks把我勾上了!

Hooks允許我們創建更小,可組合,可重用,更易管理的React組件。

您可能正在使用Hooks的一個用例是:使用useState或useReducer管理表單狀態。

讓我們考慮一個場景,您必須管理具有多個輸入的複雜表單狀態,這些表單輸入可以是幾種不同的類型,如文本,數字,日期輸入。表單狀態甚至可以具有嵌套信息,例如用戶的地址信息,它具有子字段,例如address.addressLine1,address.addressLine2等。

也許您還必須根據當前狀態更新表單狀態,例如toggle切換按鈕

現在,如果您對每個單獨的表單字段使用useState,那麼您可以根據當前狀態計算新狀態


但是,如果你有太多單獨的表單字段,比如100+,那麼這種方法並不友好。

腦補一下...


編寫單獨的useStates,然後爲每個字段使用單獨的更新函數是不切實際的。我們的另一個選擇是hook,useReducer

我們來看一個例子。


呃,不好。您不可能爲reducer中的n個表單字段編寫每個用例

但是,useReducer中使用的reducer函數只是一個返回更新狀態對象的普通函數。所以,我們可以做得更好。


這樣看起來,reducer簡潔乾淨多了。

但是,現在reducer更新參數中如果有回調函數,則不能基於當前狀態計算新狀態,因爲當前state沒有傳遞給回調函數作爲參數。就像我們在useState一樣:

useState中的更新函數可以基於prev參數計算新狀態

另外,如何更新嵌套狀態如address.addressLine1,address.pinCode。

我們通過使用不那麼理想的方法進行了很多關於管理複雜表單狀態的討論。讓我告訴你解決方案。


因此,這是處理複雜表單場景的完整源代碼。

我將稍微解釋一下reducer(enhancedReducer)函數。

reducer函數接收兩個參數,第一個參數是更新前的當前狀態。當您調用updateState / dispatch函數來更新reducer狀態時,將自動提供此參數。 reducer函數的第二個參數是用於更新state。它不一定是採用{type:'something',payload:'something'}形式的典型redux動作對象。它甚至可以是任何東西,數字,字符串,對象或函數

這就是我們的做法。如果updateArg是一個函數,我們用當前狀態調用它來計算新函數。無論我們從這個函數返回什麼對象都成爲我們的新狀態

如果updateArg是一個普通的舊Javascript對象,那麼有兩種情況。

1:該對象沒有_path和_value屬性,因此是一個普通的更新對象,就可以像使用this.setState一樣。因此,您可以使用包含要更新的狀態片段的新對象調用updateState,並將其與舊狀態合併並返回新狀態。

2:對象具有_path和_value屬性- 當使用具有這兩個屬性的對象作爲參數,調用更新回調函數時。我們將此視爲一種特殊情況,其中_path表示嵌套的字段路徑。在字符串形式中,例如:'address.pinCode'或表示路徑['address','pinCode']的數組

我們如何使用此類路徑表示來更新對象中的嵌套字段?我們將使用lodash的set方法。它接受路徑表單作爲更新和對象的有效輸入。


但是,set方法就地改變對象並且不返回新副本,但在React世界中,更改檢測取決於Immutability(不可變)。需要一個全新的數據副本,在內存中有一個新位置來觸發渲染。

爲了繞過這個,我們使用immer,來輕鬆地處理Javascript對象的不變性。


immer中的produce函數將對象作爲其第一個參數進行處理,在我們的例子中是當前狀態,它的第二個參數是一個函數,
它接收對象的草稿副本以進行mutate,無論你在這個函數內修改了什麼草稿狀態,是在副本上完成的,而不是實際的輸入對象狀態。 然後,它會自動返回包含更新數據的新對象。

這就是我們的增強版reducer。

安裝一下依賴,就可以跑起來了。

PS:在enhancedReducer中可以處理更多邊緣情況,動態字段映射也可以縮短一些代碼,減少代碼重複和其他一些事情。


參考資源:

Lodash文檔: https://lodash.com/docs/4.17....

immerjs/immer: https://github.com/immerjs/im...

還可以關注頭條號:「前端知否」

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章