setState 不更新数组

问题描述 投票:0回答:1

我正在使用reactjs创建一个todo应用程序,并且当用户单击输入时我试图更新我的todo项目列表。当用户单击时,我可以更改该项目,但该项目的状态不会更新。我不明白为什么状态不更新。我认为这与 .map() 并将 todo 对象返回到新数组有关,但我不太清楚出了什么问题。有什么想法吗?

应用程序.js

import React from 'react'
import TodoItem from './components/TodoItem'
import TodosData from './TodosData'
import './App.scss'

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      todoItems: TodosData
    }

    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(id) {
    this.setState( prevState => {
      const updatedTodos = prevState.todoItems.map( todo => {
        if (todo.id === id) {
          todo.completed = !todo.completed
        }
        return todo
      })
      return {
        todoItems: updatedTodos
      }
    })
  }

  render() {
    const todosComponents = this.state.todoItems.map( item => {
      return <TodoItem key={item.id} todo={item} handleChange={this.handleChange}/>
    })
  
    return (
      <div className="TodoList">
        {todosComponents}
      </div>
    )
  }

}

export default App;

TodosItem.js

import React from 'react'

function TodoItem(props) {

    return (
        <div className="TodoItem">
            <input 
                type="checkbox" 
                checked={props.todo.completed} 
                onChange={ () => props.handleChange(props.todo.id) }
            />
            <p>{props.todo.text}</p>
        </div>
    )
}

export default TodoItem
javascript reactjs state setstate array.prototype.map
1个回答
1
投票

问题

你正在改变你的状态对象。由于嵌套对象引用是相同的,React 会阻止渲染任何可能已更新的内容。换句话说,由于对象引用与之前的渲染相同,React 假设没有任何变化。

handleChange(id) {
  this.setState( prevState => {
    const updatedTodos = prevState.todoItems.map(todo => {
      if (todo.id === id) {
        todo.completed = !todo.completed // <-- object mutation!!
      }
      return todo
    })
    return {
      todoItems: updatedTodos
    }
  })
}

解决方案

除了浅复制数组之外,您还需要浅复制正在更新的任何嵌套状态。

handleChange(id) {
  this.setState( prevState => {
    const updatedTodos = prevState.todoItems.map(todo => {
      if (todo.id === id) {
        return {
          ...todo // <-- copy todo
          completed: !todo.completed, // <-- update propety
        }
      }
      return todo
    })
    return {
      todoItems: updatedTodos
    }
  })
}
© www.soinside.com 2019 - 2024. All rights reserved.