簡體   English   中英

復選框未更改 React 組件中的狀態

[英]Checkbox not changing state in React component

我正在使用 React 創建一個 todolist 應用程序。 待辦事項的數據如下所示:

const todoData = [
    {
        id: 1,
        text: "Empty bin",
        completed: true
    },
    {
        id: 2,
        text: "Call mom",
        completed: false
    }
]

現在,我有一個 App 組件,我可以在其中導入該數據並將其保存在狀態中。

import todoData from "./todoData"

class App extends React.Component {
  constructor() {
    super()
    this.state = {
      todos: todoData,
    }

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

我還有一個 handleChange 方法,它應該將完成的屬性的值更改為其相反的值。 例如:對於 id 為 1 的待辦事項,它的文本值為“Empty Bin”,並且已完成為 true,因此默認情況下將選中復選框。 但是,當它被點擊時,完成應該是假的,並且不再點擊復選框。 出於某種原因,這不會發生,因此完成保持其默認布爾值並且不會翻轉。 因此,當單擊復選框時不會發生任何變化。

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

        return {
          todos: updatedTodos
        }
      })
}

使用 console.log 后,我意識到 todo.completed 確實被更改為其相反的值,但由於某種原因,它沒有在 updatedTodos 中更改,即使在 devtools map() 中說當它返回一個新數組時該值已更新存儲在 updatedTodos 中。 因此,狀態不會改變並且無法單擊復選框

TodoItem 功能組件與 App 組件位於一個單獨的文件中,並包含 todo 元素的 HTML。 如下圖所示:

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

此外,TodoItem 是在 App 組件中呈現的

render() {
    const todoArray = this.state.todos.map(task => <TodoItem key={task.id} 
      task={task} handleChange={this.handleChange}/>)
    return (
      <div className="todo-list">
        {todoArray}
      </div>
    )
  }

看起來你正在改變handleChange函數中的 todo 對象

handleChange(id) {
    this.setState(prevState => {
      const updatedTodos = prevState.todos.map(todo => {
          if (todo.id === id) {
            //todo.completed = !todo.completed this is mutating
            // in react mutating a object will result in unexpected results like this.
            // so you have to create a new object based on the current todo and return it

              return {
                  ...todo,
                  completed: !todo.completed
              }
          }
          return todo
        })

        return {
          todos: updatedTodos
        }
    })
}

那里發生了什么?

數組中的每個對象都指向一個內存位置,基本上,如果我們更改對象屬性值(例如: completed ),而不更改它正在變異的內存位置,

並通過這樣做todo.completed = !todo.completed我們直接改變的值completed屬性,但仍指向同一個內存位置的待辦事項對象,所以我們做這個變異的對象,反應也不會對此作出回應,現在

 return {
    ...todo,  // <- create a new object based on todo
    completed: !todo.completed  // <- change the completed property
}

我們創建基於待辦事項的新對象{...todo} (新對象=新的存儲位置),和我們改變的值completed => {...todo, completed: !todo.completed}因為這是指向新的內存位置 react 會響應變化。

如果您不熟悉擴展運算符 ( ... ),請在此處閱讀,不要忘記查看那里的對象文字部分中的擴展

你需要傳播你的對象然后改變特定的領域

        if (todo.id === id) {
            return {
              ...todo,
              completed: !todo.completed
            }
          }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM