如何編寫高性能的 React 代碼:規(guī)則、模式、注意事項
下面將編寫一個“國家設(shè)置”頁面,用戶可以從列表中選擇國家,查看該國家的信息,可以保存國家:

可以看到,左側(cè)有一個國家列表,帶有“已保存”和“已選擇”狀態(tài),當(dāng)點擊列表中的選項時,右側(cè)會顯示該國家的詳細信息。當(dāng)按下保存按鈕時,選定的國家會變成已保存,已保存的選項的背景會變成藍色。
1. 構(gòu)建應(yīng)用程序
首先,根據(jù)設(shè)計圖,我們要考慮應(yīng)用的結(jié)構(gòu)以及要實現(xiàn)哪些組件:
頁面組件:在其中處理提交邏輯和國家選擇邏輯; 國家列表組件:將呈現(xiàn)列表中的所有國家,并進行過濾和排序等操作; 國家選項組件:將所有國家呈現(xiàn)在國家列表組件中; 選定國家組件:將呈現(xiàn)選定國家的詳細信息,并具有保存按鈕。

當(dāng)然,這不是實現(xiàn)這個頁面的唯一方式,實現(xiàn)方式僅供參考。下面就來看看如何實現(xiàn)這些組件。
2. 實現(xiàn)頁面組件
下面終于要開始寫代碼了,下面就從根開始,實現(xiàn)Page組件,步驟如下:
需要組件包含頁面標(biāo)題、國家列表和選定國家組件; 將頁面參數(shù)中的國家列表數(shù)據(jù)傳遞給CountriesList組件,以便它可以呈現(xiàn)這些數(shù)據(jù); 頁面中應(yīng)該有一個已選中國家的狀態(tài),它將從 CountriesList 件接收,并傳遞給 SelectedCountry 組件; 頁面中應(yīng)該有一個已保存國家的狀態(tài),它將從 SelectedCountry 組件接收,并傳遞給 CountriesList 組件。
export?const?Page?=?({?countries?}:?{?countries:?Country[]?})?=>?{
??const?[selectedCountry,?setSelectedCountry]?=?useState(countries[0]);
??const?[savedCountry,?setSavedCountry]?=?useState(countries[0]);
??return?(
????<>
??????Country?settings</h1>
??????
??????????????????countries={countries}
??????????onCountryChanged={(c)?=>?setSelectedCountry(c)}
??????????savedCountry={savedCountry}
????????/>
??????????????????country={selectedCountry}
??????????onCountrySaved={()?=>?setSavedCountry(selectedCountry)}
????????/>
??????</div>
????>
??);
};
3. 重構(gòu)頁面組件(考慮性能)
在 React 中,當(dāng)組件的 state 或者 props 發(fā)生變化時,組件會重新渲染。在 Page 組件中,當(dāng) setSelectedCountry 或者 setSavedCountry 被調(diào)用時,組件就會重新渲染。當(dāng)組件的國家列表數(shù)據(jù)(props)發(fā)生變化時,組件也會重新渲染。CountriesList 和 SelectedCountry 組件也是如此,當(dāng)它們的 props 發(fā)生變化時,都會重新渲染。
我們知道,React 會對 props 進行嚴(yán)格相等的比較,并且內(nèi)聯(lián)函數(shù)每次都會創(chuàng)建新值。這就導(dǎo)致了一個錯誤的的觀念:為了減少 CountriesList 和SelectedCountry 組件的重新渲染,需要通過在 useCallback 中包裝內(nèi)聯(lián)函數(shù)來避免在每次渲染中重新創(chuàng)建內(nèi)聯(lián)函數(shù)。
export?const?Page?=?({?countries?}:?{?countries:?Country[]?})?=>?{
??const?onCountryChanged?=?useCallback((c)?=>?setSelectedCountry(c),?[]);
??const?onCountrySaved?=?useCallback(()?=>?setSavedCountry(selectedCountry),?[]);
??return?(
????<>
??????...
??????????????????onCountryChanged={onCountryChange}
????????/>
??????????????????onCountrySaved={onCountrySaved}
????????/>
??????...
????</>
??);
};
而實際上,這樣并不會起作用。因為它沒有考慮到:如果父組件 Page 被重新渲染,子組件 CountriesList 也總是會重新渲染,即使它根本沒有任何 props。
可以這樣來簡化 Page 組件:
const?CountriesList?=?()?=>?{
??console.log("Re-render!!!!!");
??return?countries?list,?always?re-renders</div>;
};
export?const?Page?=?({?countries?}:?{?countries:?Country[]?})?=>?{
??const?[counter,?setCounter]?=?useState(1);
??return?(
????<>
??????Country?settings
h1>
??????瀏覽
47
評論圖片表情評價
