在reactjs和react-native我們經常發現組件狀態的錯誤使用。隨著應用程序規模擴大并變得更加復雜(例如,通過使用嵌套組件),這個問題變得尤為重要,并且最終可能會導致性能下降(損害用戶體驗)、惡劣的開發體驗。維護我們的代碼,甚至是一個充滿意外行為的有缺陷的應用程序。
發生這種情況時,通常會出現一些小問題需要比應有的時間更長的時間來修復,或者特定的解決方案會在我們的應用程序的另一個角落觸發錯誤。
今天我們將使用一個簡單但真實的錯誤場景來展示react組件狀態的錯誤實現會給我們帶來什么以及如何讓它按預期工作。在本例中,我們使用react hooks進行狀態管理。
具體情況
我們的一個組件由基本表單和將數據發送到 api 的附加邏輯組成,我們檢測到輸入的數據與我們的服務最終接收到的數據之間存在不一致。
事實證明,這是在附加到組件狀態更改的邏輯中分配的問題。更具體地說,狀態變量用于保存表單值,其內容在更新后立即在請求內發送(或嘗試更新其值,正如我們將看到的)。
這就是 react 組件的生命周期沒有被遵循:當我們更新狀態變量時,react 需要一些時間來重新渲染整個組件及其子組件(除非我們告訴它不要這樣做)每次更改都這樣做)。這就是為什么在此過程完成之前我們無法使用狀態變量。
? 更進一步,請記住,當我們指示組件中的狀態更改時,react 將此更新(以及我們可能請求的任何其他更新)排入隊列,并應用它在虛擬 dom 中,最后(通過稱為協調的過程)將其傳輸到 dom,以便我們可以在應用程序中看到更新。絕對比僅僅為變量分配新值要復雜得多。
有關組件狀態和重新渲染的更多信息,請隨時查閱文檔!
現在讓我展示一下我們的代碼:
import { usestate } from "react"; import testapi from "services" const mycomponent = (): reactelement => { const [statefuldata, setstatefuldata] = usestate<string>(""); const handleclick = async (newdata: string) => { // the problem here is that react needs some time to re-render our // component everytime statefuldata is updated (in this case through a // hook). for this reason, statefuldata is not updated by the time // we call testapi.postdata (its value will be `''`), so this // handler needs a fix. setstatefuldata(newdata); await testapi.postdata(statefuldata); } return ( <button onclick="{()"> handleclick("new data")}> click me! </button> ) } </string>
登錄后復制
可能的出路
我相信有兩條路可以解決這樣的場景。正確的值取決于狀態值更新后您需要如何處理它。
1. 移除狀態變量
如果我們不是在每次表單收到任何更改時都在組件中重新渲染,那么就不需要狀態變量,我們可以使用表單的內部數據直接使用我們的 api。
import testapi from "services" const myimprovedcomponent = (): reactelement => { const handleclick = async (newdata: string) => { // if there is no need for a re-render (and therefore for a state // variable), a possible solution is to avoid the use of the hook // and simply use the value that we receive from params. await testapi.postdata(newdata); } return ( <button onclick="{()"> handleclick("new data")}> click me! </button> ) }
登錄后復制
2. 為狀態變化附加邏輯
如果我們確實想在每次更新變量時重新渲染組件(假設我們想在屏幕上顯示其內容),那么我們需要一個狀態變量,更重要的是,我們需要添加一個#?? #useeffect當我們的變量更新以處理此事件時觸發的鉤子。
import { useState } from "react"; import TestApi from "services" const MyImprovedStatefulComponent = (): ReactElement => { const [statefulData, setStatefulData] = useState<string>(""); // If we need a state variable we have to attach our logic to its updates // through the useEffect hook This way we will be consuming TestApi only // when statefulData has been updated. useEffect(() => { // An extra validation here since this callback is not only // triggered when statefulData but also when mounting the component. // For more information check the docs! if (!!statefulData) { await TestApi.postData(statefulData); } }, [statefulData]) const handleClick = async (newData: String) => { setStatefulData(newData); } return ( <button onclick="{()"> handleClick("New data")}> Click me! <div>{statefulData}</div> </button> ) } </string>
登錄后復制
結束語
這里解決的問題是組件狀態管理不良的結果。由于
react 生命周期階段沒有得到尊重,我們的組件在存儲在其狀態中的數據與附加到用戶交互的排隊狀態更新的預期結果之間出現了滯后。
總之,良好實踐的使用以及組件對官方
react文檔的調整至關重要。正確的狀態管理,srp后組件的原子化(單一職責原則,dry后邏輯集中(don’t repeat yourself)與外部組件解耦,實現高度內聚的內部邏輯是最大限度地減少問題解決時間、降低錯誤率并允許應用程序穩定性和可擴展性的實踐。
圖片取自官方
reactdocs.