使用setState()修改一个JavaScript数组将更新第二个状态数组

时间:2020-07-21 10:28:56

标签: javascript arrays reactjs

我的React App显示一个可供选择的名称网格。当我选择一个名称时,它将读取一个数据库并显示适用于该名称的数据行。每行都是一个对象,该对象存储为单个数组元素。 我有两个包含对象的数组,一个是“原始数据”,另一个是“修改后的数据”。然后,我将它们进行比较,以查看在更新数据库之前行之一是否发生了更改。 数组的定义如下:

constructor(props) {
    super(props);
    this.state = {
        ...
        detail_data: [],
        old_detail_data: []
    }
}

当我选择一行时,会调用_handleRowClick():

_handleRowClick(i) {
    if (i >= 0) {
        this.getRecord(i, (err, res) => {
            if (!err) {
                let detail = res.body;
                this.setState({
                    name_detail: Object.assign({}, detail),  // Stores details about the name
                    selectedIndex: i
                })
                // Fetch the Career Directions
                this.fetchSingleCareerDirections(this.state.detail.animal_code);  // Gets the rows
            }
        })
    }
}

fetchSingleCareerDirections(animal_code) {
    request.get(`/lookup/career_directions/${animal_code}`, (err, res) => {
        let data = [].concat(res.body);  // row data
        this.setState({
            detail_data: [...data],      // array 1
            old_detail_data: [...data],  // array 2
        });
    });
}

至此一切都很好,我的数据在detail_data和old_detail_data中符合预期。因此,我在一行中修改了一条数据,在这种情况下,单击复选框(对于有效的职业),但是对行数据的任何更改都具有相同的效果:

<td>
    <input type="checkbox"
        checked={item.valid_career == 'Y' ? true : false}
        style={{ width: 30 }}
        name={"valid_career|" + i}
        onChange={(e) => { this._setTableDetail("valid_career", e.target.checked == true ? 'Y' : 'N', i) }}
    />
</td>

哪个调用更新例程_setTableDetail()将'Y'或'N'存储到detail_data数组中:

_setTableDetail(name, value, index) {
    let _detail_data = Object.assign([], this.state.detail_data);
    _detail_data[index][name] = value;
    this.setState({ detail_data: _detail_data });
}

这将按预期更新 this.state.detail_data 。但是,如果我查看 this.state.old_detail_data ,也对该数组进行了精确的更改。同样,作为测试,如果我修改更新了detail_data的old_detail_data。 之所以必须这样做,是因为两个数组都引用相同的内存空间。但是我看不到这是怎么回事。如上所示,我的setState()例程执行此操作:

this.setState({
    detail_data: [...data],
    old_detail_data: [...data],
});

据我所知,这使用散布运算符在每个实例中创建一个新数组。那么这两个数组都如何引用相同的内存空间?可能与我在setState()调用内进行克隆有关吗?

1 个答案:

答案 0 :(得分:0)

非常感谢@Anthony的评论。在我出问题的地方,你说的很对。因此,尽管我的数组是唯一的,但它们包含的对象却引用了内存中的相同对象。

我修改了fetchSingleCareerDirections()函数的代码来解决此问题:

fetchSingleCareerDirections(animal_code) {
    request.get(`/lookup/career_directions/${animal_code}`, (err, res) => {
        let data = [].concat(res.body);
        this.setState({
            detail_data: data.map(row => Object.assign({}, row)),      // array 1
            old_detail_data: data.map(row => Object.assign({}, row)),  // array 2
        });
    });
}

该程序现在可以正常运行了。

仅需注意一点。我正在使用JavaScript的较旧版本,但散布运算符无法正常工作(非常糟糕)。但是按照建议,事先在其他地方进行测试,我可以使用安东尼的代码,这是一种更好的现代方法:

fetchSingleCareerDirections(animal_code) {
    request.get(`/lookup/career_directions/${animal_code}`, (err, res) => {
        let data = [].concat(res.body);
        this.setState({
            detail_data: data.map(row => ({ ...row })),      // spread operator
            old_detail_data: data.map(row => ({ ...row })),  // spread operator
        });
    });
}