問題描述:
在某個組件中.有可能頻繁的取數據(但是數據未改變,因此不需要更新). 數據的頻繁請求會觸發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> )
} ) ;