技术干货|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 代码有帮助。

相关文章
相关标签/搜索