# React子组件性能优化

4 min read
Table of Contents

在 React 中,父组件的重新 render 会引发子组件的重新 render。

子组件的重新渲染

类组件

import React from 'react'
class Child extends React.Component {
render() {
console.log('child render')
return <>This is Child Component</>
}
}
export default class App extends React.Component {
state = {
count: 0,
}
handleClick = () => {
this.setState({
count: this.state.count + 1,
})
}
render() {
return (
<>
<div>
<button onClick={this.handleClick}>click me</button>
count: {this.state.count}
</div>
<Child />
</>
)
}
}

函数组件

import React, { useState } from 'react'
function Child() {
console.log('child render')
return <>This is Child Component</>
}
export default function App() {
const [count, setCount] = useState(0)
return (
<>
<div>
<button onClick={() => setCount(count + 1)}>click me</button>
count: {count}
</div>
<Child />
</>
)
}

在上面的类组件和函数组件中,我们点击按钮 click,会刷新 count 值,导致父组件刷新,而子组件没有做任何状态的变化,但是也一并重新渲染。

为了避免不必要的渲染更新,提高渲染效率,有三个主要的方式:

  • shouldComponentUpdate
  • PureComponent
  • React.memo

类组件

React.PureComponent

class Child extends React.PureComponent {
render() {
console.log('child render')
return <>This is Child Component</>
}
}

React.PureComponent 会以浅层对比 props 和 state 的方式实现函数。如果赋值了组件相同的 props 和 state,PureComponent 则可以提高性能,不进行重复渲染。

PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的对比结果。

且 PureComponent 中将跳过所有子组件树的 props 更新,因此确保所有子组件也是 PureComponent。

shouldComponentUpdate

class Child extends React.Component {
shouldComponentUpdate() {
return false
}
render() {
console.log('child render')
return <>This is Child Component</>
}
}

通过使用 shouldComponentUpdate(nextProps, nextState) 进行对比,通过最终返回的 boolean 值决定是否重新渲染。

此方法仅作为性能优化的方式而存在,可以将 this.props 与 nextProps 以及 this.state 与 nextState 进行比较,并返回 false 跳过更新。返回 false 并不会阻止在 state 更改时重新渲染。

不建议经常使用 shouldComponentUpdate

函数组件

React.memo

React.memo 是一个高阶组件,所以它的语法如下:

const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
})
const Child = React.memo(function Child() {
console.log('child render')
return <>This is Child Component</>
})

如果组件在相同的 props 的情况下渲染相同的结果,那么可以通过包装在 React.memo 中调用,以此通过记忆组件渲染结果来提高组件的性能。React.memo 仅检查 props 变更,如果实现中拥有 useState、useReducer或useContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。

参考链接


More Posts

# useMemo 和 useCallback

5 min read

useCallback 和 useMemo 是 react 里面 Hook 的一部分,通常被作为性能优化使用。它们可以用来缓存函数、组件、变量,以减少两次渲染的重复计算。

# TypeScript中的泛型

3 min read

泛型(generics),在 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的组件。