在这个例子中,我们在父组件Father的state对象中设置了一个numberArray的数组,并且将数组元素通过map函数传递至三个子组件Son中,作为其显示的内容(标题1,2,3),点击每个Son组件会更改对应的state中numberArray的数组元素,从而使父组件重渲染,继而导致子组件重渲染
demo:(点击前)
点击1后:
控制台输出:
demo如我们设想,但这里有一个我们无法满意的问题:输出的(1,1,2),有我们从0变到1的数据,也有未发生变化的1和2。这说明Son又做了两次多余的重渲染,但是对于1和2来说,它们本身state没有变化(也没有设state),同时父组件传达的props也没有变化,所以我们又做了无用功。
那怎么避免这个问题呢?没错,关键还是在shouldComponentUpdate这个钩子函数上
import React from 'react'
class Son extends React.Component{
shouldComponentUpdate(nextProps,nextState){
if(nextProps.number == this.props.number){
return false
}
return true
}
render(){
const {index,number,handleClick} = this.props
//在每次渲染子组件时,打印该子组件的数字内容
console.log(number);
return <h1 onClick ={() => handleClick(index)}>{number}</h1>
}
}
class Father extends React.Component{
constructor(props) {
super(props);
this.state = {
numberArray:[0,1,2]
}
}
//点击后使numberArray中数组下标为index的数字值加一,重渲染对应的Son组件
handleClick = (index) => {
let preNumberArray = this.state.numberArray
preNumberArray[index] += 1;
this.setState({
numberArray:preNumberArray
})
}
render(){
return(<div style ={{margin:30}}>{
this.state.numberArray.map(
(number,key) => {
return <Son
key = {key}
index = {key}
number ={number}
handleClick ={this.handleClick}/>
}
)
}
</div>)
}
}
export default Father
这次只打印了数字发生改变的numberArray[0]对应的Son组件,说明numberArray[1],numberArray[2]的重渲染被“过滤”了!(goodjob!)
【注意】:nextProps.number == this.props.number不能写成nextProps == this.props,它总返回false因为它们是堆中内存不同的两个对象。(对比上面的红色的【注意】)
【总结】
一句话总结以上例子的结论:前后不改变state值的setState(理论上)和无数据交换的父组件的重渲染都会导致组件的重渲染,但你可以在shouldComponentUpdate这道两者必经的关口阻止这种浪费性能的行为
在这种简单的情景下,只要利用好shouldComponent一切都很美好,但是当我们的state中的numberArray变得复杂些的时候就会遇到很有意思的问题了,让我们把numberArray改成
[{number:0 }, {number:1 }, {number:2 } ]
这种对象数组的数据形式,整体的代码结构仍然不变:
import React from 'react' class Son extends React.Component{ shouldComponentUpdate(nextProps,nextState){ if(nextProps.numberObject.number == this.props.numberObject.number){ return false } return true } render(){ const {index,numberObject,handleClick} = this.props //在每次渲染子组件时,打印该子组件的数字内容 console.log(numberObject.number); return <h1 onClick ={() => handleClick(index)}>{numberObject.number}</h1> } } class Father extends React.Component{ constructor(props) { super(props); this.state = { numberArray:[{number:0 }, {number:1 }, {number:2 } ] } } //点击后使numberArray中数组下标为index的数字值加一,重渲染对应的Son组件 handleClick = (index) => { let preNumberArray = this.state.numberArray preNumberArray[index].number += 1; this.setState({ numberArray:preNumberArray }) } render(){ return(<div style ={{margin:30}}>{ this.state.numberArray.map( (numberObject,key) => { return <Son key = {key} index = {key} numberObject ={numberObject} handleClick ={this.handleClick}/> } ) } </div>) } } export default Father
这个时候发现无论如何点击三个标题均无变化(没有数字改变),且控制台无输出!