ES6 / React:为什么我的三层嵌套setState更新不起作用?

时间:2018-01-25 23:39:05

标签: javascript arrays reactjs ecmascript-6 spread-syntax

我有一个具有三个嵌套属性的状态对象,我需要一次仅更新值。所以我使用ES6扩展语法来更新状态,但出于某种原因,每当我运行它时,它都会给我未定义的属性类型错误。

当我只有两个嵌套属性时,它工作正常。有什么问题?

method(type, row, col) {
        this.setState({
            changedCells: {
                ...this.state.changedCells,
                [type]: {
                    ...this.state.changedCells[type],
                    [row]: {
                        ...this.state.changedCells[type][row],
                        [col]: true
                    }
                }
            }
        }
}

当changedCells状态最初为空时。并且setState方法是这样的,用星号表示,它运行正常。但是在我的第一个例子中,cellState为空,而type =' wood',row = 0,col = 0,它不起作用,但在第二个例子中起作用。

method(type, row, col) {
        this.setState({
            changedCells: {
                ...this.state.changedCells,
                [type]: {
                    ...this.state.changedCells[type],
                    [row]: {
                        ...this.state.changedCells[row], ***CHANGED***
                        [col]: true
                    }
                }
            }
        }
}

1 个答案:

答案 0 :(得分:2)

假设您的初始状态为:

this.state = {
    changedCells: {}
};

然后您的财产访问评估如下:

this.state.changedCells评估为{}

this.state.changedCells[type]评估为未定义

this.state.changedCells[type][row] TypeError:无法读取未定义的属性行

您的代码之前有效,因为您可以在undefined上使用spread运算符:

{...undefined} === {}

您可以通过两种方式解决问题。初始化状态以包含它需要的每个typerow,例如

this.state = {
    changedCells: {
        typeA: {
            row1: {
                col1: false
            }
        }
    }
}

等等。如果你有一套明确定义的类型,行和列,这很好,但如果你有很多或者不知道他们的名字,那就不切实际了。

另一个选项是在对象可能未定义时提供默认的空对象:

method(type, row, col) {
    this.setState({
        changedCells: {
            ...this.state.changedCells,
            [type]: {
                ...this.state.changedCells[type],
                [row]: {
                    ...(this.state.changedCells[type] || {})[row],
                    [col]: true
                }
            }
        }
    }
}

有一些工具可以让您的生活更轻松。您可以使用lodash get来检索属性,并提供默认值。

method(type, row, col) {
    this.setState({
        changedCells: {
            ...(_.get(this.state, "changedCells", {})),
            [type]: {
                ...(_.get(this.state, ["changedCells", type], {})),
                [row]: {
                    ...(_.get(this.state, ["changedCells", type, row], {})),
                    [col]: true
                }
            }
        }
    }
}