当我将对象重新分配给现有对象时,状态更新但不会触发渲染

时间:2020-01-10 00:33:14

标签: reactjs

Source Code

这有效

const { id, title, complete, updated_at } = todoItem
...
todoItems[todoItemIndex].title = title
todoItems[todoItemIndex].complete = complete
todoItems[todoItemIndex].updated_at = updated_at
this.setState({ todoItems })

这行不通

todoItems[todoItemIndex] = todoItem
this.setState({ todoItems })

todoItems[todoItemIndex] = { ...todoItem }
this.setState({ todoItems })

this.setState(state => {
    todoItems: state.todoItems.map(item => {
        if (item.id === todoItem.id) {
            item = { ...todoItem }
        }
        return item
    })
})

其他说明

当我使用componentDidUpdate()时,我打电话给this.state.todoItems来确认todoItems[todoItemIndex] = { ...todoItem }实际上正在被更新。

componentDidUpdate() {
    console.log(this.state.todoItems)
}

2 个答案:

答案 0 :(得分:0)

总是以不可变的方式更新您的状态,因此当前解决方案和其他to选项无效。 最后一个解决方案的问题是您忘记了将return放进去,或者甚至把圆括号放在了由更新程序func返回的对象上。

以您的情况

  Private Sub tbemail_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles tbemail.Validating

    Dim pattern As String = "^[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z|0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*\.([a-z][a-z|0-9]*(\.[a-z][a-z|0-9]*)?)$"


    Dim match As System.Text.RegularExpressions.Match = Regex.Match(tbemail.Text.Trim(), pattern, RegexOptions.IgnoreCase)
    If (match.Success) Then
    Else
        MessageBox.Show("Please enter a valid email id", "Checking")
        e.Cancel = True
    End If
End Sub

答案 1 :(得分:0)

感谢ryanhinerman 如下所述their answer on Reddit

更好的解决方案是不将props中的数据保存在构造函数中。而是直接使用this.props.todoItem。如果要使其看起来更漂亮,可以在TodoItem的render函数的顶部对其进行解构,如下所示:const { todoItem } = this.props;


这里实际发生的事情将很难解释,但这对您对React的理解很重要,因此希望我可以做一个很好的解释。

constructor(props) { 
    super(props);
    this.todoItem = this.props.todoItem;
}

在最初创建组件时,只会在组件的生命周期内一次调用此构造函数。您在这里要做的是在初始创建时使用this.props.todoItem并将其保存在组件中。此构造函数将不会再次被调用,因此this.todoItems不管this.props.todoItems changes有多少次都不会被更新。

<TodoItem todoItem={todoItem} key={todoItem.id} /> 在这里,我们为组件提供了一个密钥,并且当密钥更改时,React知道可以重新创建我们的组件。由于id的{​​{1}}从未更改,因此React不会重新创建该组件。如果我们要使用todoItem.title或其他名称,则密钥将更改,整个组件将被重置,构造函数将被再次调用,以“解决”问题。但是,这不是正确的解决方案。

更好的解决方案是不将props中的数据保存在构造函数中。而是直接使用todoItem。如果要使其看起来更漂亮,可以在TodoItem的render函数的顶部对其进行解构,如下所示:const this.props.todoItem