组件渲染性能优化
在本小节,我们将会探讨组件在渲染时,如何优化渲染性能问题。
涉及到的内容会包含 shouldComponentUpdate、PureComnent、React.memo、useMemo、useCallback 等。
shouldComponentUpdate 与 PureComnent
shouldComponentUpdate 与 PureComnent 都与类组件相关,所以下面会以类组件来示例。
import React, {
Component } from 'react'
export default class App extends Component {
constructor() {
super();
this.state = {
counter: 1
}
}
render() {
console.log("App 渲染了");
return (
<div>
<h1>App 组件</h1>
<div>{
this.state.counter}</div>
<button onClick={
() => this.setState({
counter : 1
})}>+1</button>
</div>
)
}
}
在上面的代码中,我们书写了一个简单的计数器,按钮在点击的时候仍然是设置 counter 的值为 1,不过,虽然 counter 的值没有变,整个组件仍然是重新渲染了的。显然,这一次渲染是没有必要的。
此时,我们就可以使用 shouldComponentUpdate 来进行优化。
文档地址:https://zh-hans.reactjs.org/docs/react-component.html#shouldcomponentupdate
当 props 或 state 发生变化时,shouldComponentUpdate 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate 方法时不会调用该方法。
下面我们来使用 shouldComponentUpdate 优化上面的示例:
import React, {
Component } from 'react'
import {
objectEqual } from "./utils/tools"
export default class App extends Component {
constructor() {
super();
this.state = {
counter: 1
}
}
/**
*
* @param {*} nextProps 新的 props
* @param {*} nextState 新的 state
* @returns
*/
shouldComponentUpdate(nextProps, nextState) {
// shouldComponentUpdate会根据返回值来决定是否重新渲染
// 默认是 true,要重新渲染
// 如果返回 false,则不会重新渲染
// 我们就需要将当前的 props 和 state 与新的 props 和 state 进行一个比较
if (objectEqual(this.props, nextProps) && objectEqual(this.state, nextState)) {
// 如果新旧 props 和 state 都是相同的,那么就返回 false,不需要重新渲染
return false;
}
return true;
}
render() {
console.log("App 渲染了");
return (
<div>
<h1>App 组件</h1>
<div>{
this.state.counter}</div>
<button onClick={
() => this.setState({
counter: Math.floor(Math.random() * 3 + 1)
})}>+1</button>
</div>
)
}
}
在上面的代码中,我们在类组件中书写了一个 shouldComponentUpdate 的生命周期钩子函数,该函数会在渲染执行之前被调用,函数内部能够接收到新的属性和新的状态,我们要做的就是让新的属性和状态和当前的属性以及状态进行浅比较,如果相同则返回 false,也就是不重新渲染。
此方法仅作为性能优化的方式而存在,不要企图依靠此方法来“阻止”渲染。另外,现在 React 官方已经提供了 PureComponent,因此一般情况下我们是不需要手写 shouldComponentUpdate 的。
PureComponent 文档:https://zh-hans.reactjs.org/docs/react-api.html#reactpurecomponent
React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate( ),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。
例如我们将上面的示例直接修改为 PureComponent,如下:
import React, {
PureComponent } from 'react'
export default class App extends PureComponent {
constructor() {
super();
this.state = {
counter: 1
}
}
render() {
console.log("App 渲染了");
return (
<div>
<h1>App 组件</h1>
<div>{
this.state.counter}</div>
<button onClick={
() => this.setState({
counter: Math.floor(Math.random() * 3 + 1)
})}>+1</button>
</div>
)
}
}
可以看到,效果相同,但是代码精简了很多。在使用 PureComponent 的时候,有一点一定要注意,这也是官方所强调,就是内部做的是浅比较,这意味下面的代码是无法更新的:
import React, {
PureComponent } from 'react'
export default class App extends PureComponent {
constructor() {
super();
this.state = {
stu: ["张三", "李四"]
}
}
addStuHandle = () => {
this.state.stu.push("王武");
this.</