what!!!我的代码结构明明没有任何变化啊,只是改传递数字为传递对象而已。嗯嗯,问题就出在这里,我们传递的是对象,关键在于nextProps.numberObject.number == this.props.numberObject.number这个判断条件,让我们思考,这与前面成功例子中的nextProps.number == this.props.number的区别:
1numberObject是一个对象
2.number是一个数字变量
3数字变量(number类型)和对象(Object类型)的内存存储机制不同
javascript变量分为基本类型变量和引用类型变量
对于number,string,boolean,undefined,null这些基本类型变量,值存在栈中:
对于object,Array,function这些引用类型变量,引用存在栈中,而不同的引用却可以指向堆内存中的同一个对象:
然后我们回过头再去看刚才的问题,在上面,nextProps.numberObject和this.props.numberObject的实际上指向的是同一个堆内存中的对象,所以点击标题时在多次判断条件中nextProps.numberObject.number==this.props.numberObject.number 等同于0 == 0 --> 1 == 1--> 2 == 2,所以总返回true,导致每次点击 调用shouldComponentUpdate()函数时都阻止了渲染,所以我们才看不到标题变化和控制台输出。
怎么才能保证每次取到不同的numberObject?
我们有三种方式:
1.ES6的扩展语法Object.assign()//react官方推荐的es6写法
2深拷贝/浅拷贝或利用JSON.parse(JSON.stringify(data))//相当于深拷贝,但使用受一定限制,具体的童鞋们可自行百度
3 immutable.js//react官方推荐使用的第三方库,目前github上20K star,足见其火热
4 继承react的PureComponent组件
1ES6的扩展语法Object.assign()
object.assign(TargetObj,obj1,obj2 ...)[返回值为Oject]可将obj1,obj2等组合到TargetObj中并返回一个和TargetObj值相同的对象,比如
let obj = object.assign({},{a:1},{b:1})//obj为{a:1,b:1}
import React from 'react' class Son extends React.Component{ shouldComponentUpdate(nextProps,nextState){ (nextProps.numberObject.number == this.props.numberObject.number){ console.log('前一个对象' + JSON.stringify(nextProps.numberObject)+ '后一个对象' + JSON.stringify(this.props.numberObject)); 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 //把做修改的number Object先拷贝到一个新的对象中,替换原来的对象 preNumberArray[index] = Object.assign({},preNumberArray[index]) //使新的number Object对象的number属性加一,旧的number Object对象属性不变 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
点击0后打印1,问题解决!
2深拷贝/浅拷贝或利用JSON.parse(JSON.stringify(data))
在这里先不多介绍了,大家可自行百度...
3immutable.js —— react官方推荐的第三方库:
先让我们回到困扰我们的问题的根源 —— 两个引用类型变量的赋值表达式和两个基本类型变量的赋值表达式不同。
对于基本类型变量a和b, b = a 后,访问a,b相当于访问两个不同的变量,两者彼此毫无关联