1. 使用shouldComponentUpdate避免重复渲染
以下代码,只有在count为3的时候才会触发更新
class ClassChild extends React.Component {
constructor() {
super();
}
render() {
console.log('classchild render');
return <div>ClassChild</div>
}
}
function FuncChild() {
console.log('funcchild render');
return <div>FuncChild</div>
}
export default class Page1 extends React.Component {
constructor() {
super();
this.state = {
count: 0,
}
}
shouldComponentUpdate(nextProps, nextState) {
if(nextState.count === 3) {
return true;
}
return false;
}
add = () => {
this.setState({
count: this.state.count + 1
});
}
render() {
console.log('page1 render');
return <div>
<h1>Page1</h1>
<button onClick={this.add}>add</button>
<ClassChild></ClassChild>
<FuncChild></FuncChild>
</div>;
}
}
大部分情况下,你可以使用React.PureComponent而不必写你自己的shouldComponentUpdate,它只做一个浅比较。但是当你比较的目标为引用类型数据,浅比较会忽略属性或状态突变的情况。
class ClassChild extends React.PureComponent {
constructor() {
super();
}
render() {
console.log('classchild render');
return <div>ClassChild</div>
}
}
如果是Function组件的话,你可以使用React.memo实现同样的效果:
function Child() {
console.log('funcchild render');
return <div>FuncChild</div>
}
const FuncChild = React.memo(Child);
2. 属性传递优化
下面代码中,尽管ClassChild已经使用PureComponent优化了,count改变后还是会重新渲染ClassChild,是因为父组件更新后,执行render方法,ClassChild中传入的属性都是新的属性。
class ClassChild extends React.PureComponent {
render() {
console.log('classchild render');
return <div>ClassChild</div>
}
}
export default class Page1 extends React.PureComponent {
constructor() {
super();
this.state = {
count: 0
}
}
add = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return <div>
<h1>Page1 count:{this.state.count}</h1>
<button onClick={this.add}>add</button>
<ClassChild style={{color: 'red'}}></ClassChild>
</div>;
}
}
因此最好将style属性提取到constructor中,如下:
class ClassChild extends React.PureComponent {
constructor() {
super();
this.style = {color: 'red'};
}
render() {
console.log('classchild render');
return <div>ClassChild</div>
}
}
export default class Page1 extends React.PureComponent {
constructor() {
super();
this.state = {
count: 0
}
}
add = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return <div>
<h1>Page1 count:{this.state.count}</h1>
<button onClick={this.add}>add</button>
<ClassChild style={this.style}></ClassChild>
</div>;
}
}
3. 使用useCallback给函数做缓存
以下代码每次改变count后,尽管ClassChild已经使用了React.PureComponent, ClassChild还是会重新进行渲染,那是因为父组件Page2每次进行更新的时候,声明的add方法都是个新的方法~
import React, { useState, useCallback } from 'react';
export default function Page2() {
const [count, setCount] = useState(0);
const add = () => {
setCount(count+1);
};
return <div>
<h1>Page2 count:{count}</h1>
<button onClick={add}>add</button>
<ClassChild add={add}></ClassChild>
</div>;
}
因此需要使用useCallback对函数进行缓存,此时改变count,ClassChild不会重新渲染.(useCallback的第二个参数是依赖项,用法同useEffect,只有当依赖项变化后,才会产生新的方法)
import React, { useState, useCallback } from 'react';
export default function Page2() {
const [count, setCount] = useState(0);
const add = useCallback(() => {
setCount(count+1);
}, []);
return <div>
<h1>Page2 count:{count}</h1>
<button onClick={add}>add</button>
<ClassChild add={add}></ClassChild>
</div>;
}
4. 使用useMemo给计算的值做缓存
以下代码中,每次修改count后,expensive方法都会重新执行,这样会做很多无效的计算。
import React, { useState, useMemo } from 'react';
export default function Page2() {
const [count, setCount] = useState(0);
const [title, setTitle] = useState('hhh');
const add = () => {
setCount(count+1);
}
const expensive = () => {
console.log('expensive函数执行');
var sum = 0;
for(let i = 0; i < 100000; i++) {
sum++;
}
return `title是: ${title}`;
};
return <div>
<h1>Page2 count:{count}</h1>
<button onClick={add}>add</button>
<ClassChild add={add} expensive={expensive()}></ClassChild>
</div>;
}
而实际上expensive方法只需要在title变化的时候才需要重新计算,因此可以使用useMemo来给计算的值做缓存
import React, { useState, useMemo } from 'react';
class ClassChild extends React.PureComponent {
constructor() {
super();
}
render() {
console.log('classchild render');
return <div>ClassChild {this.props.expensive}</div>
}
}
export default function Page2() {
const [count, setCount] = useState(0);
const [title, setTitle] = useState('hhh');
const add = () => {
setCount(count+1);
}
const expensive = useMemo(() => {
console.log('expensive函数执行');
var sum = 0;
for(let i = 0; i < 100000; i++) {
sum++;
}
return `title是: ${title}`;
}, [title]);
return <div>
<h1>Page2 count:{count}</h1>
<button onClick={add}>add</button>
<ClassChild add={add} expensive={expensive}></ClassChild>
</div>;
}