在React开发中遇到了一个问题:
需求是在一个选择组件中选择数据mydata
数组,确定后将mydata
数组返回到父组件,再次打开该选择组件时,从父组件获取之前选择的数据mydata
并显示为已选择。
/* 打开选择组件 */
showModal = () => {
this.setState({
comVisible: true
});
const { mydata } = this.props;
this.setState({
mydata: mydata
});
console.log(this.state.mydata);
this.onChange();
}
/* 确定-将data返回父组件 */
handleOk = () => {
if (this.state.mydata.length > 0) {
this.setState({
comVisible: false
});
// 返回父组件data
this.props.getMyData({
mydata: this.state.mydata,
...
});
} else {
message.error("data is null");
}
}
/* 取消-不对data做操作 */
handleCancel = () => {
this.setState({
comVisible: false
});
}
/* 选择data */
onChange = (mydata) => {
let mydata = this.state.mydata;
Object.keys(otherdata).forEach((title) => {
...
// 对mydata做一些改变
});
this.setState({
mydata
});
}
大概流程如下:
按照逻辑,在选择组件中选择mydata
,触发onChange
事件,将此时改变的mydata
设置为state.mydata
,点击确定后触发handleOk
函数,将state.mydata
传给父组件。但若点击取消,则触发handleCancel
,不做任何操作。
那么问题来了,我点击了取消,再次打开选择组件,从父组件取mydata
的值,取到的是点击取消之前选择的mydata
值。按理说点击了取消不做操作,该值是不会传给父组件的,但是为什么从父组件会取到改变后的值呢?
经过一系列尝试后发现,问题的原因在于数组的表现形式就是内存中的一段连续的内存地址,数组名称其实就是连续内存地址的首地址。在onChange
中对mydata
和state.mydata
的改变会直接改变该数组所指向的地址中的数据,而父组件中的mydata
也是指向该数组的,所以一旦state.mydata
发生改变,即使不将改变后的mydata
传给父组件,父组件的mydata
也会改变。
修改:给父组件传值时使用中间变量,并且数组赋值时,使用先结构再赋值的方式生成新的数组。
/* 打开选择组件 */
showModal = () => {
this.setState({
comVisible: true
});
const { mydata } = this.props;
this.setState({
mydata: mydata
});
this.onChange();
}
/* 确定-将data返回父组件 */
handleOk = () => {
if (this.state.mydata.length > 0) {
// 返回父组件data,改变后的中间变量
this.props.getMyData({
mydata: this.state.tempdata,
...
});
} else {
message.error("data is null");
}
}
/* 取消-不对data做操作 */
handleCancel = () => {
...
}
/* 选择data */
onChange = (mydata) => {
// 改变赋值方式
let mydata = [];
mydata.push(...this.state.mydata);
Object.keys(otherdata).forEach((title) => {
...
// 对mydata做一些改变
});
// 使用中间变量,不直接修改state.mydata
this.setState({
tempdata: mydata
});
}
总结:
在JS中,
数组和对象是地址型变量
数组和对象是地址型变量
数组和对象是地址型变量
基础知识一定时刻记在脑子里。。。