送给React开发者十九条性能优化建议
笔者是一个 react 重度爱好者,在工作之余,也看了不少的 react 文章, 写了很多 react 项目 ,接下来笔者讨论一下 React 性能优化的主要方向和一些工作中的小技巧。送人玫瑰,手留余香,阅读的朋友可以给笔者点赞,关注一波 。陆续更新前端文章。
1. 组件卸载前进行清理操作
在组件中为 window 注册的全局事件, 以及定时器, 在组件卸载前要清理掉, 防止组件卸载后继续执行影响应用性能.
需求:使用 useState 保存一个数值,然后开启定时器改变数值,卸载组件查看定时器是否还在运行。
import React, {
useState, useEffect } from "react"
import ReactDOM from "react-dom"
const App = () => {
let [index, setIndex] = useState(0)
useEffect(() => {
let timer = setInterval(() => {
console.log(index)
setIndex(++index)
}, 1000)
return () => clearInterval(timer)
}, [])
return (
<button onClick={
() => ReactDOM.unmountComponentAtNode(document.getElementById("root"))}>
{
index}
</button>
)
}
export default App
2. 使用纯组件降低组件重新渲染的频率
什么是纯组件
相同的输入 (state、props) 呈现相同的输出. 在输入内容相同的情况下纯组件不会被重新渲染.
如何实现纯组件
React 提供了 PureComponent 类, 类组件在继承它以后, 类组件就变成了纯组件。纯组件会对 props 和 state 进行浅层比较, 如果上一次的 props、state 和下一次的 props、state 相同, 则不会重新渲染组件.
什么是浅层比较
浅比较指的是比较基本数据类型是否具有相同的值, 比如1是否等于1, true是否等于true. 比较复杂数据类型的第一层值是否相同。
浅层比较难道没有性能消耗吗
和进行 diff 比较操作相比,浅层比较将消耗更少的性能。diff 操作会重新遍历整颗 virtualDOM 树, 而浅层比较值操作当前组件的 state 和 props。
需求:在状态对象中存储 name 值为张三,组件挂载完成后将 name 属性的值再次更改为张三,然后分别将 name 传递给纯组件和非纯组件,查看结果。纯组件只渲染一次,非纯组件会一秒打印一次
import React from "react"
export default class App extends React.Component {
constructor() {
super()
this.state = {
name: "张三"}
}
updateName() {
setInterval(() => this.setState({
name: "张三"}), 1000)
}
componentDidMount() {
this.updateName()
}
render() {
return (
<div>
<RegularComponent name={
this.state.name} />
<PureChildComponent name={
this.state.name} />
</div>
)
}
}
class RegularComponent extends React.Component {
render() {
console.log("RegularComponent")
return <div>{
this.props.name}</div>
}
}
class PureChildComponent extends React.PureComponent {
render() {
console.log("PureChildComponent")
return <div>{
this.props.name}</div>
}
}
3. 使用 React.memo 进行组件缓存
React.memo 是一个高阶组件
.
什么是高阶组件 Higher Order Component ( HOC )
高阶组件是 React 应用中共享代码, 增加逻辑复用的一种方式. 比如 A 组件和 B 组件都需要使用一个相同的逻辑,如何将逻辑抽取到一个公共的地方呢?答案就是使用高阶组件。
高阶组件的核心思想就是在组件的外层再包裹一层执行逻辑的组件,在外层组件中执行逻辑,再将逻辑执行的结果传递到内层组件。
高阶组件形式是一个函数,接收组件作为参数, 返回一个新的组件. 参数组件就是需要复用逻辑的组件,函数内部返回的新组件就是执行逻辑的组件,在新组件内部执行完逻辑以后再调用参数组件并将逻辑结果传递给参数组件。Image
函数名通常以 with 开头, 接收的组件形参名称为 WrappedComponent, 返回的组件名称和函数名称一样, 只不过 with 中的 w 要大写.
import React from "react"
export class A extends React.Component {
render() {
return <div>{
this.props.sizes.join("-")}</div>
}
}
export class B extends React.Component {
render() {
return <div>{
this.props.sizes.join("-")}</div>
}
}
const WrappedA = withResizable(A)
const WrappedB = withResizable(B)
function withResizable(WrappedComponent) {
class WithResizable extends React.Component {
constructor() {
super()
this.state = {
sizes: [window.innerWidth, window.innerHeight]
}
this.updateSizes = this.updateSizes.bind(this)
}
updateSizes() {
this.setState({
sizes: [window.innerWidth, window.innerHeight]
})
}
componentDidMount() {
window.addEventListener("resize", this.updateSizes)
}
render() {
return <WrappedComponent sizes={
this.state.sizes} />
}
}
return WithResizable
}
import React from "react"
export default class App extends React.Component {
render() {
return (
<div>
<WrappedA />
<WrappedB />
</div>
)
}
}
React.memo 介绍
与 PureComponent 相似, 如果上一次输入的 props 和下一次输入的 props 相同, 则组件不会重新渲染, 从而使组件更高效.
PureComponent 应用于类组件, React.memo 应用于函数组件.
React.memo 使用的也是使用浅层比较.
React.memo 使用
import React, {
useState, useEffect,