问题描述:
在某个组件中.有可能频繁的取数据(但是数据未改变,因此不需要更新).数据的频繁请求会触发render函数,造成性能消耗模拟代码如下
export class CommentList extends Component {
constructor(props
) {
super(props
);
this.state
= {
comments
: []
}
}
componentDidMount() {
setInterval(() => {
this.setState({
comments
:[
{ body
: '奇怪的栗子', author
: 'odd marron'},
{ body
: '好吃的栗子', author
: 'nice marron'}
]
})
}, 1000)
}
render() {
return (
<div
>
{this.state
.comments
.map((c
,i
)=>(
<Comment key
={i
} data
={c
} />
))}
</div
>
)
}
}
class Comment extends React.Component{
console
.log('render comment');
render(){
return (
<div
>
<p
> {this.props
.data
.body
} </p
>
<p
> --- {this.props
.data
.author
} </p
>
</div
>
)
}
}
可以看到,数据在未改变时,频繁的调用render
解决方案1
React 15.3之前(无PureComponent)使用shouldComponentUpdate在shouldComponentUpdate中判断当前body是否和传入的数据相等.
class Comment extends React.Component{
shouldComponentUpdate(nextProps) {
if(nextProps.data.body === this.props.data.body &&
nextProps.data.author === this.props.data.author) {
return false;
}
return true;
}
render() {
return (
<div>
<p> {data.body} </p>
<p> --- {data.author} </p>
</div>
);
}
}
解决方案2
PureComponent解决方案对上面代码修改后如下
import React, { Component } from 'react';
// 容器组件
export class CommentList extends Component {
constructor(props) {
super(props);
this.state = {
comments: []
};
}
componentDidMount() {
setTimeout(() =>{
this.setState({
comments: [
{ body: "奇怪的栗子" , author: "odd marron" },
{ body: "好吃的栗子", author: "nice marron" }
]
});
}, 1000)
}
render() {
return (
<div>
{this.state.comments.map((c,i) => (
<Comment key={i} {...c} />
))}
</div>
);
}
}
// 展示组件
class Comment extends React.PureComponent{
render() {
console.log('render comment');
return (
<div>
<p>{this.props.data.body}</p>
<p>--- {this.props.data.author}</p>
</div>
)
}
}
此时数据为改变时 不更新.
注意:
使用PureComponent时,其传递的参数只能是基本类型引用或简单的非多层嵌套对象原因见下面PureComponent源码:
import shallowEqual
from './shallowEqual'
import Component
from './Component'
export default function PureComponent(props
, context
) {
Component
.call(this, props
, context
);
}
PureComponent
.prototype
= Object
.create(Component
.prototype
);
PureComponent
.prototype
.constructor
= PureComponent
;
PureComponent
.prototype
.isPureReactComponent
= true;
PureComponent
.prototype
.shouldComponentUpdate
= shallowCompare
;
function shallowCompare (nextProps
, nextState
) {
return !shallowEqual(this.props
, nextProps
) ||
!shallowEqual(this.state
, nextState
);
}
export default function shallowEqual(objA
, objB
) {
if(objA
=== objB
){
return true
}
if(typeof objA
!=='object' || obja
=== null || typeof objB
!== 'objB' || objB
=== null) {
return false
}
var keysA
= Object
.keys(objA
);
var keysB
= Object
.keys(objB
);
if(keysA
.length
!== keysB
.length
){
return false
}
for(var i
= 0; i
< keysA
.length
; i
++ ){
if(!objB
.hasOwnproperty(keysA
[i
]) || objA
[keysA
[i
]] !== objB
[krysA
[i
]] ){
return false;
}
}
return true;
}
PureComponent 对shouldComponentUpdate进行设置.比较引用地址然后比较第一层…因此使用PureComponent时,应注意将对象结构出来使用
解决方案3
React.memo (React v16.6.0以上)React.memo是个高阶函数更改上面Comment
const Comment
= React
.memo((props
) => {
console
.log('render comment');
return (
<div
>
<p
>{props
.body
}</p
>
<p
> --- {props
.author
}</p
>
</div
>
)
});