一 什么时候会重新渲染UI
- 对于类组件,不管state变没变,只要调用了this.setState,就会重新render。
因此类组件很容易有多余的render。shuouldComponentUpdate这个钩子可以解决该问题,可以在这个钩子里面对比新旧state以及新旧props,从而判断是否需要render。或者使用React.PureComponent也自带解决这个问题的功能, React.PureComponent中以浅层对比 (shallowEqual)prop 和 state的方式来实现了该函数。
import React from 'react'
class App extends React.Component{
constructor(props){
super(props);
this.state={n:1};
}
add=()=>{
//state没有变,但是setState了,所以每次都会打印render
this.setState(this.state)
}
render(){
console.log('render了');
return(
<>
<div>{this.state.n}</div>
<button onClick={this.add}>+1</button>
</>
)
}
}
export default App;
可以理解为,只要state传给this.setState之后,react都会把其值赋值给一个新的对象。因此类组件并不知道state是旧的引用还是新的引用,因为类组件的setState都会将传进来的旧引用变成一个新的引用。
- 对于函数组件,只有setState的参数的引用变了,才会重新render
import React, { useState } from "react";
export default function App() {
const [data, setData] = useState({ n: 1 });
const add = () => {
//这样写会重新渲染
// setData({ n: data.n + 1 });
//这样写不会渲染,因为data的引用没有变
//所以不要修改state!!!!!创建新的state
//可以使用immer.js,创建新对象写起来就像是在修改原对象
data.n+=1;
setData(data);
};
console.log("render了");
return (
<div className="App">
<div>{data.n}</div>
<button onClick={add}>+1</button>
</div>
);
}
二 总结
- state内容变了的时候。
直接修改state,引用可以不变,不推荐。创建新对象,引用变化,会正常render。 - 什么时候render?
类组件看到一个或多个setState就会render。函数组件发现state引用变了才会render。 - render做了什么?
render会创建虚拟DOM,经过diff,最后选择性的更新真实DOM。
所以多余的render很可能不会浪费多少性能。阻止render的代码如果写的太复杂了,可能比render还要耗性能。