Javascript 反应状态正在意外更改
我有一个列表(新闻),它来自服务器,每个对象都有多个用户可以编辑的字段。我在名为Javascript 反应状态正在意外更改,javascript,reactjs,state,Javascript,Reactjs,State,我有一个列表(新闻),它来自服务器,每个对象都有多个用户可以编辑的字段。我在名为originalData的状态下保存列表,在名为activeNews的状态下保存第一条新闻: componentDidMount(){ fetch('/api/published/news_published_english').then(res => res.json()).then(news =>{ if(news && news.rows[0]){
originalData
的状态下保存列表,在名为activeNews
的状态下保存第一条新闻:
componentDidMount(){
fetch('/api/published/news_published_english').then(res => res.json()).then(news =>{
if(news && news.rows[0]){
const new_news = [...news.rows];
this.setState({originalData:[...news.rows]});
this.setState({activeNews:new_news[0].doc.content});
}
});
}
当用户单击另一个新闻项目时,activeNews
将更改为所选索引handleChange
获取用户要在活动新闻项中更改的字段索引及其值:
handleChange(index, value) {
const x = [...this.state.news];
x[index].value = value;
this.setState({ news: x });
console.log("original", this.state.originalData);
console.log("news", news);
}
现在的问题是为什么originalData
会随着用户更改的值不断更新?我希望originalData
不更改,但它在handleChange函数中不断更改
这是我在originalData
上调用setState
的唯一地方,但它不断更改为传递给handleChange
的值
this.setState({ originalData: [...news.rows] });
这是react应用程序中的常见错误,您正在创建数组
This.state.news
的副本,该数组是一个对象数组
执行x[index].value=value
时,实际上是在修改仍在this.state.news
中引用的原始对象
这-->constx=[…This.state.news]代码>复制阵列但不复制对象,它们仍在引用原始对象
你需要做的事情是这样的:
const news = this.state.news.map((x, i) => {
if (i === index) {
return {...x, value};
} else return x
})
this.setState({ news })
handleChange(index, value) {
this.setState(state => (
{ news: state.news.map((item, i) => i === index
? { ...item, value }
: item
}
));
}
这是react应用程序中的常见错误,您正在创建数组This.state.news
的副本,该数组是一个对象数组
执行x[index].value=value
时,实际上是在修改仍在this.state.news
中引用的原始对象
这-->constx=[…This.state.news]代码>复制阵列但不复制对象,它们仍在引用原始对象
你需要做的事情是这样的:
const news = this.state.news.map((x, i) => {
if (i === index) {
return {...x, value};
} else return x
})
this.setState({ news })
handleChange(index, value) {
this.setState(state => (
{ news: state.news.map((item, i) => i === index
? { ...item, value }
: item
}
));
}
执行此操作时,您正在对handleChange
函数中的原始对象进行变异:
x[index].value = value;
为了更好地展示正在发生的事情,我将稍微扩展您的代码
handleChange(index, value) {
const copiedArray = [...this.state.news];
const originalObject = copiedArray[index];
originalObject.value = value;
this.setState({ news: copiedArray });
}
正如我在这里用变量名回避的那样,即使您已经创建了一个新的数组-this.state.news[index]
和copiedaray[index]
处的对象是同一个对象-.value
的更改将在这两个位置发生更改。为了解决这个问题,您需要进行深度克隆。您可以通过查找一个库(如lodash)来实现这一点,也可以采用更快的解决方案并按如下方式更改代码:
handleChange(index, value) {
const copiedArray = [...this.state.news];
const originalObject = copiedArray[index];
const copiedObject = Object.assign({}, originalObject);
copiedObject.value = value;
copiedArray[index] = copiedObject;
this.setState({ news: copiedArray });
}
或同一事物的浓缩版本:
handleChange(index, value) {
const arr = [...this.state.news];
arr[index] = { ...arr[index], value };
this.setState({ news: arr });
}
执行此操作时,您正在对handleChange
函数中的原始对象进行变异:
x[index].value = value;
为了更好地展示正在发生的事情,我将稍微扩展您的代码
handleChange(index, value) {
const copiedArray = [...this.state.news];
const originalObject = copiedArray[index];
originalObject.value = value;
this.setState({ news: copiedArray });
}
正如我在这里用变量名回避的那样,即使您已经创建了一个新的数组-this.state.news[index]
和copiedaray[index]
处的对象是同一个对象-.value
的更改将在这两个位置发生更改。为了解决这个问题,您需要进行深度克隆。您可以通过查找一个库(如lodash)来实现这一点,也可以采用更快的解决方案并按如下方式更改代码:
handleChange(index, value) {
const copiedArray = [...this.state.news];
const originalObject = copiedArray[index];
const copiedObject = Object.assign({}, originalObject);
copiedObject.value = value;
copiedArray[index] = copiedObject;
this.setState({ news: copiedArray });
}
或同一事物的浓缩版本:
handleChange(index, value) {
const arr = [...this.state.news];
arr[index] = { ...arr[index], value };
this.setState({ news: arr });
}
在代码中,x[index].value=value
正在修改原始数组,这就是它被破坏的原因。您可以这样编写更改处理程序:
const news = this.state.news.map((x, i) => {
if (i === index) {
return {...x, value};
} else return x
})
this.setState({ news })
handleChange(index, value) {
this.setState(state => (
{ news: state.news.map((item, i) => i === index
? { ...item, value }
: item
}
));
}
请注意,我在setState中使用回调函数,当您的新状态依赖于以前的状态时,建议使用此函数
编辑实际上,不需要映射整个数组,因为您已经知道索引。请看caesay的答案,从性能上看,哪一个更好:
handleChange(index, value) {
this.setState(state => {
const newsCopy = [ ...state.news ];
newsCopy [index] = { ...arr[index], value };
return { news: newsCopy };
});
}
在代码中,x[index].value=value
正在修改原始数组,这就是它被破坏的原因。您可以这样编写更改处理程序:
const news = this.state.news.map((x, i) => {
if (i === index) {
return {...x, value};
} else return x
})
this.setState({ news })
handleChange(index, value) {
this.setState(state => (
{ news: state.news.map((item, i) => i === index
? { ...item, value }
: item
}
));
}
请注意,我在setState中使用回调函数,当您的新状态依赖于以前的状态时,建议使用此函数
编辑实际上,不需要映射整个数组,因为您已经知道索引。请看caesay的答案,从性能上看,哪一个更好:
handleChange(index, value) {
this.setState(state => {
const newsCopy = [ ...state.news ];
newsCopy [index] = { ...arr[index], value };
return { news: newsCopy };
});
}
如下面提供的答案所示。。您永远不应该改变当前状态变量。。复制它们,更新值,然后将新值设置为state,如下所示。。您永远不应该改变当前状态变量。。复制它们,更新值,然后将新值设置为stateHi,我经常看到类似这样的代码-->this.state.news.map((item,I)=>I==index?value:item})
你能解释一下这实际上是如何工作的吗?这是修改当前项中的值
属性的缩写吗?@deook:它的作用与您在回答中所做的相同,只是它使用了条件(三元)运算符@caesay,但这不会导致数组包含未修改的对象,然后只包含值
,即[{…},{…},'someValue']
?@deowk是的,在本例中,这是一个bug-它应该是这样的:this.state.news.map((item,i)=>i==index?{……item,value}:item})代码>大家好,我经常看到类似的代码-->this.state.news.map((item,I)=>I===index?value:item})
您能解释一下这是如何工作的吗?这是修改当前项中的值
属性的缩写吗?@deook:它的作用与您在回答中所做的相同,只是它使用了条件(三元)运算符@caesay,但这不会导致数组包含未修改的对象,然后只包含值
,即[{…},{…},'someValue']
?@deowk是的,在本例中,这是一个bug-它应该是这样的:this.state.news.map((item,i)=>i==index?{……item,value}:item})代码>