我有一个列表(新闻),它来自服务器,每个对象都有多个字段,用户可以编辑。我将列表保存为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函数中不断变化!

这是我在setState上调用originalData的唯一地方,但它不断更改为传递给handleChange的值。

this.setState({ originalData: [...news.rows] });

最佳答案

执行此操作时,您正在对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 });
}

09-25 20:50