当更改通过props传递的数组的长度时,'shouldComponentUpdate'函数无法检测到数组长度的变化。我知道"shouldComponentUpdate"无法检测嵌套对象属性的更改,但这是一个简单的数组长度!!这是React中的一个bug吗??
https://jsfiddle.net/ashraffayad/cLz1q8sv/
var ArrTest = React.createClass({
render: function() {
return <div >{this.props.arr}< /div>;
},
shouldComponentUpdate: function(nextProps) {
console.log(this.props.arr.length, nextProps.arr.length); // same length !!!
return true;
}
});
// - - - - app component
var App = React.createClass({
getInitialState: function() {
return {
arr: [1, 2, 3, 4]
};
},
render: function() {
return <ArrTest arr={ this.state.arr } />;
},
componentDidMount: function() {
var self = this;
setTimeout(function() {
self.state.arr.push(7);
self.setState(self.state);
}, 2000);
}
});
ReactDOM.render( < App /> ,
document.getElementById('container')
);
这不是React中的错误,而是代码的问题。永远不要直接修改this.state
值。
试试这个:
componentDidMount: function() {
var self = this;
setTimeout(function() {
self.setState({arr: self.state.arr.concat([7])});
}, 2000);
}
它有效。因为React在传递道具时不会克隆道具,所以对数组的更改会反映在它的所有引用上。
我建议您在Javascript中阅读更多关于不变性的内容。
简而言之,永远不要做this.state.[anything].push/pop/shift/unshift()
,永远不要。改为这样做:
var arr = this.state.arr.slice(); // Create a copy of the array
arr.push(2); // do whatever you want to do
this.setState({ arr: arr }); // pass changes to React
仅仅因为有两个引用(this.props.arr
、nextProps.arr
)并不意味着有两个实例。
当您使用push更改数组时,您将修改实例。当shouldComponentUpdate
运行时,它会比较引用,因为它们指向同一个实例,所以数组长度是相同的。
如果你想传递一个具有不同元素或属性的新数组,那么你也需要创建一个新数组。
用push
代替concat
是很容易的。
setTimeout(function() {
self.setState({
arr: self.state.concat([7])
}, 2000);
您在if
中引用了相同的数组,即,您正在修改相同的数组而不是创建新的数组,并且您正在shouldComponentUpdate
中处理对相同数组的两个引用。
您应该始终将props和state视为不可变的,因此使用.concat
创建一个新数组,而不是推到处于状态的数组上,可以解决当前的问题。
setTimeout(function () {
this.setState({arr: this.state.concat([7])});
}.bind(this), 2000);
如果您在shouldComponentUpdate
中执行this.props.arr === nextProps.arr
,您会看到数组将彼此相等。