繁体   English   中英

反应状态发生意外变化

[英]React state is changing unexpectedly

我有一个列表(新闻),它来自服务器,每个对象都有多个字段,用户可以编辑。 我将列表保存在一个名为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] });

这是this.state.news应用程序中的一个常见错误,您正在创建数组this.state.news的副本,该数组是对象的数组。

当您执行x[index].value = value时,实际上是在修改仍在this.state.news中引用的原始对象。

这-> const x = [...this.state.news]; 复制数组但不复制对象,它们仍在引用原始对象。

您需要做的是这样的:

const news = this.state.news.map((x, i) => {
  if (i === index) {
    return {...x, value};
  } else return x
})
this.setState({ news })

执行此操作时,您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]copiedArray[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修改了原始数组,这就是它被破坏的原因。 您可以这样编写更改处理程序:

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 };
    });
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM