目录
React.memo(FunComponent,compareFunction)
PureComponent
把继承类从 Component 换成 PureComponent 即可,可以减少不必要的 render 操作的次数,从而提高性能。
当父组件更新时,如果传入子组件的 props 和 state 都没发生改变(通过下面shallowEqual函数浅层比较),render方法就不会触发,省去 Virtual DOM 的生成和比对过程。
简单的实现
function shallowEqual(obj1, obj2) {
if (Object.keys(obj1).length !== Object.keys(obj2).length){
return false;
}
//不用for in是由于它会遍历对象原型上的属性。
const keys = Object.keys(obj1)
for (let key of keys) {
if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
}
示例
下面在定时器中不断对父组件的count进行加1,传入子组件Pure和NoPure的属性虽然没有变,但不是继承于PureComponent的组件会重新触发render函数,会每隔1s重新输出1遍'Component'字符串。
import React, { Component ,PureComponent} from 'react'
class Pure extends PureComponent {
render() {
console.log("PureComponent")
return (
<div>
标题:{this.props.title}
</div>
)
}
}
class NoPure extends Component {
render() {
console.log("Component")
return (
<div>
标题:{this.props.title}
</div>
)
}
}
export default class Purememo extends Component {
constructor(props){
super(props)
this.state={
title:'shouldComponentUpdate使用',
count:0
}
}
componentDidMount(){
setInterval(()=>{
this.setState({
count:this.state.count+1
})
},1000)
}
render() {
return (
<div>
<p>{this.state.count}</p>
<Pure title={this.state.title}></Title>
<NoPure title={this.state.title}></Count>
</div>
)
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Purememo />, rootElement);
注意
在class组件内,只有那些状态和属性不经常的更新的组件才会用PureComponent进行优化,对于经常更新的,这样处理后反而浪费性能,因为每一次浅比较也是要消耗时间的。
React.memo(FunComponent,compareFunction)
和类组件中的PureComponent作用相同,用于减少不必要的 render 操作的次数。
FunComponent为函数子组件;
compareFunction为自定义的比较函数,可以不传,默认比较函数组件的传入属性。该函数还默认接收2个参数,一个是改变前的属性值,和变化后的属性值,当返回为false时,组件才会重新渲染。
示例
下面在定时器中不断对父组件的count进行加1,传入子组件Child中的属性虽然没有变,会重新渲染,(打开Child组件注释)会每隔1s重新输出1遍I am rendering'字符串。而使用了React.memo后通过areEqual函数比较传入的prop属性的变化,当返回false时,该组件才会重新渲染。
import React, { component } from "react";
function Child({seconds}){
console.log('I am rendering');
return (
<div>I am update every {seconds} seconds</div>
)
};
function areEqual(prevProps, nextProps) {
if(prevProps.seconds===nextProps.seconds){
return true
}else {
return false
}
}
const ChildMemo = React.memo(Child,areEqual)
export default class Example extends Component {
constructor(props){
super(props)
this.state={
title:'shouldComponentUpdate使用',
count:0
}
}
componentDidMount(){
setInterval(()=>{
this.setState({
count:this.state.count+1
})
},1000)
}
render() {
return (
<div>
<p>{this.state.count}</p>
<ChildMemo title={this.state.title}></ChildMemo >
{/* <Child seconds={1}></Child> */}
</div>
)
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);
React.useMemo(callback,array)
useMemo的返回值是一个记忆值,是callback的返回值。
- 不传数组,每次更新都会重新计算
- 空数组,只会计算一次
- 依赖对应的值,当对应的值发生变化时,才会重新计算(可以依赖另外一个 useMemo 返回的值)
示例
每次点击setCount,count加1。当点击更新时,由于add依赖于memoValue变量改变了,会使add重新计算,渲染新的add值。
function App () {
const [ count, setCount ] = useState(0)
const [ memoValue, setmemoValue ] = useState(false)
const add = React.useMemo(() => count + 1, [memoValue])
return (
<div>
点击次数: { count }
<br/>
次数加一: { add }
<button onClick={() => { setCount(count + 1)}}>点我</button>
<button onClick={() => { setmemoValue(!memoValue)}}>点我更新</button>
</div>
)
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);