技術乾貨|7個 React 性能提高技巧


前言
React 是由 Facebook 團隊主導開發的UI框架,做爲當前三大前端框架(另外兩個是 Angular、Vue )之一,提供了數據驅動的 UI 開發模式,以及組件化的開發方式,能夠構建高性能的前端應用。
拍樂雲音視頻 PaaS 雲平臺爲用戶提供了 Console 控制檯,控制檯提供了應用管理、用量查看、費用管理、數據羅盤、用戶管理等功能。控制檯前端的開發選擇了 React 做爲基礎框架。在使用 React 過程當中,咱們總結了 React 性能提高的7個技巧,在這裏和你分享。前端

熟記 Diffing 規則react

1.當節點(包括 DOM 節點和組件節點)的類型發生變化時,React 會卸載該節點(包含子節點)的 DOM 樹,而後從新渲染新的 DOM 樹。數組

2.當 DOM 節點的類型不變時,React 會保留 DOM 節點,而後對比屬性變化更新 DOM 節點。
3.當組件節點的類型不變時,組件實例會保持不變,對比 props 屬性而後更新組件。
4.上面過程從根節點開始,遞歸到全部的葉子節點結束。
從上面的規則咱們能夠看出,組件是主角,後面的性能提高點也是圍繞組件的。從上面的規則能夠看出大變更應該使用不一樣的組件,小變更應該修改屬性。記住了 Diffing 規則其實就能夠寫出性能不錯的 React 代碼。上面只是一個總結,不須要能夠詳細看看這遍文檔協調。性能優化

key前端框架

更新時 React 須要對比更新先後的變化,生成一個 mutation。沒有 key,不能複用以前的組件,影響性能。框架

用數組索引來做爲 key,因爲是基於索引來決定組件的更新和複用,順序變化時會致使非受控組件變化達不到預期,好比指望第一個元素和第二個元素對調位置,因爲數組索引做爲 key,非受控組件是複用的(後面有個性能提高技巧就是使用非受控組件),React 識別不出來位置變化,這裏有個例子演示了索引做爲 key 致使的問題。函數

最佳實踐是在列表層使用惟一值做爲 key,例如 id。組件化

合理地拆分組件性能

咱們知道 React 提供了組件式開發方式。寫好 React 代碼的基礎就是組件拆分,合理地組件拆分既能夠提高的代碼可維護性和可複用性,結合後面的性能技巧,還能夠提高性能。優化

1.組件拆分一個重要的原則是高內聚低耦合,子組件應該是一個獨立的單元,子組件與父親組件間的通訊信息要少,數據請求應該放到子組件中,除非父組件也要使用。

function Page(props) => {

return <Card>
    <MeetingInfo id={props.match.params.id} />
    <UserList />
</Card>;

}
function MeetingInfo(props) {

const { info, setInfo } = useState({});
useEffect(() => {
    getMeeting(props.id).then(res => {
        setInfo(res);
    });
});

return <>
    {
        // 這裏顯示meetingInfo
    }
</>;

}
2.會複用的單元必定要抽成組件,複用組件應該不依賴外部,所以只經過 props 進行通訊,若是要使用到 context 能夠用一個高階組件進行包裹。
3.組件粒度也不該過細,會增長組件層級深度,也會增長維護的工做量。
4.爲了統同樣式,應該優先考慮抽取公用的類名,而不是組件。

合併setState

合併 setState 能夠減小 render 執行次數,是一種很直接、也很明顯的性能提高方式。
同一代碼塊中不要屢次調用 setState

// 調用了屢次setState
this.setState(state => {

pagination: {
    ...state.pagination,
    current: 1,
}

}, () => {

this.setState({
    loading: true,
});
getData().then(res => {
    // ...
})

});

// 合併setState
this.setState(state => {

pagination: {
    ...state.pagination,
    current: 1,
},
loading: true,

}, () => {

getData().then(res => {
    // ...
})

});
同時發出的請求,尤爲當這些請求耗時差很少時,可使用 Promise.all 合併,從而減小 setState 次數
// 合併前
getMeeting().then(info => this.setState({ info }));
getUserList().then(userList => this.setState({ info }));

// 合併後
Promise.all([

getMeeting(),
getUserList(),

]).then(([info, userList]) => {

this.setState({
    info,
    userList,
});

});

避免在 render 中作複雜的計算

理想的狀況,render 只作數據的展現,實際開發中或多或少會有一些計算,可是要避免在 render 中作複雜的計算,而應該把值計算好存儲在 state 或者 props 中。

// 再render中作了構建樹的計算
function DeptTree(props) {

return <Tree data={buildTree(props.list)} />

}

// 應該把樹結構數據計算好存儲在state中
function DeptTree(props) {

const { treeData, setTreeData } = useState();
useEffect(() => {
    setTreeData(buildTree(props.list));
}, [ props.list ]);
return <Tree data={treeData} />

}

使用 PureComponent

PureComponent 更新前會淺比較 props 和 state 是否發生變化,若是沒有發生變化時則不調用 render ,從而達到提高性能的目的。

import { useState } from 'react';
import Child from './Child';

function Component() {
const [ num, setNum ] = useState(1);
return <div>

<div>
  <button onClick={() => setNum(num + 1)}>添加({num})</button>
</div>
<Child />

</div>;
}

export default Component;
// child.js
import React from 'react';

class Child extends React.PureComponent {
render() {

console.log('render')
return <div>子組件</div>;

}
}

export default Child;
由於使用了 PureComponent ,每次 num 增長,子組件的 render 並不會調用。PureComponent 作的是淺比較,所以要使用不可變數據。

使用非受控組件

咱們先看下什麼是受控組件,就是子組件的狀態由依賴父組件,這樣會致使須要更新子組件時,必須先改變父組件的狀態,也就是觸發父組件的 render,針對這種狀況應該考慮是否能夠設計爲非受控組件,其實造成父子組件,大部分狀況確定是要通訊的,爲了不造成受控關係,可使用 context(一般使用 Redux ,簡化了 context 的使用)進行通訊,常見的彈框,控制彈框顯示的值父組件是不須要使用的,經過把這個放在 context 中,能夠在彈框的打開和關閉不觸發父組件的 render ,能夠很明顯的提高性能,如下是示意代碼。

// addSuccess是一個固定不變的函數,所以這個組件是個非受控組件
<Add onSuccess={this.addSuccess} />
function Add(props) {

return <Modal visible={ props.addVisible }>
    {
        // ...
    }
</Modal>;

}

export default connect(state => ({

addVisible: state[namespace].addVisible,

}))(Add)

總結

以上總結的性能提高技巧,合併 setState、使用 PureComponent、使用非受控組件都是經過減小 render 次數來達到性能優化的,也是主要的性能方向。固然合併 setState 爲了性能優化犧牲了代碼的可讀性,大型項目建議採用,小型項目能夠權衡取捨。最後一個使用非受控組件是爲了下降父子組件之間的耦合(也就是合理地拆分組件)而總結出來的,不但提高了代碼的可維護性還提高了性能。但願閱讀完這篇文章能對你寫出高性能的 React 代碼有幫助。

相關文章
相關標籤/搜索