原文永久鏈接: https://github.com/AttemptWeb.....
下面說到的React開發中注意的問題,部分是自己遇到過的點,部分是收集的,也算是React代碼優化部分,這次做一個整理,希望可以幫助到你
- 1.shouldComponentUpdate
- 2.React.PureComponent
- 3.不可變Immutable
- 4.React的key標識
- 5.虛擬化長列表
- 6.React.memo函數組件
- 7.不濫用props和state
- 8.拆分組件
#避免重復渲染
當組件的props 或者 state 改變時,可能會出現重復setState的情況,對於重復的操作,我們可以通過下面的方法來避免重復渲染:
#shouldComponentUpdate
shouldComponentUpdate 返回true,確認真實DOM需要改變時,返回true。一般的做法是比較組件的props和state是否真的發生變化,如果發生變化則返回true,否則返回false。
shouldComponentUpdate(nextProps, nextState) { if (this.props.id !== nextProps.id) { return true; } if (this.state.type !== nextState.type) { return true; } return false; }
React文檔:shouldComponentUpdate()
React文檔:shouldComponentUpdate 的作用
#React.PureComponent
React.PureComponent,不必寫你自己的shouldComponentUpdate,它提供了一個淺比較。如果對象中包含復雜的數據結構,則有可能因為無法檢查深層的差別,產生錯誤的比對結果。在你的 props 和 state 較為簡單時,可以使用 React.PureComponent。(補充:當你比較的目標為引用類型數據,淺比較會忽略屬性或狀態)
class ChildComponent extends React.PureComponent { render() { return( <>{this.state.type}</> ) } }
#不可變Immutable
不可變Immutable,Immutable Data 就是一旦創建,就不能再被更改的數據。對 Immutable 對象的任何修改或添加刪除操作都會返回一個新的 Immutable 對象。更多詳情:Immutable 詳解及 React 中實踐
import { Map, is } from 'immutable'; constructor() { this.state = { // 創建 不可變Immutable data: Map({ times: 0 }) } } shouldComponentUpdate(nextProps, nextState) { for (const key in nextState) { // 通過 is 或者 !== 來比對 if (this.state[key] !== nextState[key] && !is(this.state[key], nextState[key])) { return true; } } } handleAdd() { // 一個全新的對象 const newData = this.state.data.update('times', v => v + 1); this.setState({ data: newData); }
不可變Immutable,目前我還沒有在項目中嘗試過,內容來源於社區,如果有相關文章,可以推薦給我。
#組件優化
#React的key標識
key 幫助React識別哪些元素改變了,比如被添加或刪除。因此你應當給數組中的每一個元素賦予一個確定的標識。對於列表組件,key 最好是這個元素在列表中擁有的一個獨一無二的字符串。
listData.map((item) => <li key={item.id}> {item.text} </li> );
列表組件 Diff比對時,使用元素在數組中的下標作為 key,列表順序發生修改,就代表原來的React節點組件無法復用,須創建新的React.Element節點,這樣diff 會變得慢。
當基於下標的組件進行重新排序時,組件基於它們的 key 來決定是否更新以及復用,如果 key 是一個下標,那么修改順序時會修改當前的 key,導致組件的 state(比如輸入框)可能相互篡改導致無法預期的變動。
#虛擬化長列表
虛擬列表是常見的‘長列表'和'復雜組件樹'優化方式,它優化的本質就是減少渲染的節點。只渲染當前視口可見元素。
虛擬列表適用場景:無限滾動列表, 表格,下拉列表,大數據量或無限嵌套的樹等。
相關組件方案:
react-virtualized react-window
#React.memo
隨着React的版本不斷升級,函數式組件功能越來越強大,這也符合它的最初提倡的UI = fn(e)
。隨着Hooks、memo的支持,函數組件已非常的成熟。
React.memo為高階組件,可以使用它替換現有的函數組件。它與 React.PureComponent 非常相似,但它適用於函數組件,但不適用於 class 組件。
function areEqual(prevProps, nextProps) { /* 如果把 nextProps 傳入 render 方法的返回結果與 將 prevProps 傳入 render 方法的返回結果一致則返回 true, 否則返回 false */ } function Component(props) { } React.memo(Component, areEqual)
第一個參數是函數組件,第二個參數非必須,主要是props的比較。默認情況下其只會對復雜對象做淺層對比,如果你想要控制對比過程,那么請將自定義的比較函數通過第二個參數傳入來實現。
#不濫用props和state
不論是 props和state 盡量只傳需要的數據,避免多余的更新。對於項目的后期維護特別重要。(我已經踩坑了。。。)
<ListInfoCard data={...state}>
#拆分組件
列表組件、表單組件、商品卡片、icon組件,盡量做到適度的拆分,業務組件和展示組件的分離,易於后期的維護和迭代,同時也可以提升性能。在平時開發中,對於一個單獨的頁面,數據量不大,直接將業務和展示組件捆綁在一起,在初期,這個是無關痛癢的,如果是一次性開發,問題也不是特別大,但是一旦去要后期的迭代優化,就有問題了。
#結束
自己遇到開發方面的問題基本就這些了,上面提到的基本都是我遇到過的和研究過的,希望可以幫助到你。這些只是React項目代碼層面的東西,如果你需要做一些優化方面的工作,也可以從打包、編譯入手。
ps: 順便推一下自己的個人公眾號:Yopai,有興趣的可以關注,每周不定期更新,分享可以增加世界的快樂