问题描述:
在某个组件中.有可能频繁的取数据(但是数据未改变,因此不需要更新). 数据的频繁请求会触发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> ) }
}
解决方案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> )
} ) ;