簡體   English   中英

如何在不改變數組的情況下更新此狀態?

[英]How can I update this state without mutating the array?

我想知道如何在以下情況下改變狀態:

我正在使用 React Hooks。 我有一個TodoList ,其中列出TodoItems 可以單擊TodoItems來運行一個名為toggle的函數,該函數可以切換它們的completed屬性。

import React, { useState } from "react";
import TodoItem from "./TodoItem";

export default function TodoList() {
  const [todos, setTodos] = useState([
    { text: "Example", completed: false }
  ]);

  const toggle = index => {
    const newTodos = [...todos];
    newTodos[index].completed = !newTodos[index].completed; // Mutating state?
    setTodos(newTodos);
  };

  return (
    <>
      {todos.map((item, index) => (
        <TodoItem key={index} index={index} todo={item} toggle={toggle} />
      ))}
    </>
  );
}

有人告訴我這是變異狀態:

你創建了一個 todos 數組的副本,但你仍然改變了數組中的一個項目:

 newTodos[index].completed = !newTodos[index].completed;

傳播數組只會創建數組的淺拷貝,但是原始的 todo 對象沒有被復制,因此發生了變異。

那么,在不改變狀態的情況下處理這個問題的正確方法是什么? 我試過傳入一個prevTodos參數,但是狀態沒有更新:

const toggle = index => {
  setTodos(prevTodos => {
    prevTodos[index].completed = !prevTodos[index].completed;
    return prevTodos;
  });
};

更新:我看過你們推薦的帖子。 這是一個解決方案,盡管我想知道是否有更簡潔的表達方式:

const toggle = index => {
  setTodos(
    todos.map((todo, i) =>
      i === index ? { ...todo, completed: !todo.completed } : todo
    )
  );
};

更新2:謝謝大家。 我在下面發布了解決方案。 StackOverflow 不會讓我接受 2 天,但我會這樣做。 建議帖子上接受的答案建議使用第三方庫,並且它不使用 React Hooks,所以我不認為這個問題是重復的。

找到了解決辦法。 map將返回一個不同的數組,您可以收聽 index 參數(在我下面的代碼片段中,這是i )以收聽當前索引並更改您的目標對象。

const toggle = index => {
  setTodos(
    todos.map((todo, i) =>
      i === index ? { ...todo, completed: !todo.completed } : todo
    )
  );
};

這些線程幫助我拼湊起來:

感謝所有幫助過的人。

沒錯,避免這個問題最簡單的方法就是避免變異數據

一種方法是使用函數式方法,特別是使用非變異數組方法,如.map

 function TodoList() { const [todos, setTodos] = React.useState([{ text: "Example", completed: true }]); const toggle = index => { const updatedTodos = todos.map((todo, i) => { if (i === index) { todo.completed = !todo.completed; } return todo; }); setTodos(updatedTodos); }; return ( <React.Fragment > {todos.map((item, index) => ( <p key={item.text} onClick={() => toggle(index)} className={item.completed ? "completed" : ""} > {item.text} </p> ))} </React.Fragment> ); } ReactDOM.render( < TodoList / > , document.getElementById('root'))
 .completed { text-decoration: line-through; }
 <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> <div id="root"></div>

const toggle = (index) => {
  const oldTodo = todos[index];
  setTodos(oldState => {
   oldState.splice(index, 1, {...oldTodo, checked: !oldTodo.checked})

   return oldState
})
}

暫無
暫無

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

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