簡體   English   中英

如何在對象數組中使用 usestate 更新 state?

[英]How to update state with usestate in an array of objects?

我在使用 React useState 掛鈎時遇到了一些問題。 我有一個帶有復選框按鈕的 todolist,我想將 'done' 屬性更新為 'true',它的 id 與 'clicked' 復選框按鈕的 id 相同。 如果我 console.log 我的 'toggleDone' function 它會返回正確的 ID。 但我不知道如何更新正確的屬性。

當前的 state:

const App = () => {

  const [state, setState] = useState({
    todos: 
    [
        {
          id: 1,
          title: 'take out trash',
          done: false
        },
        {
          id: 2,
          title: 'wife to dinner',
          done: false
        },
        {
          id: 3,
          title: 'make react app',
          done: false
        },
    ]
  })

  const toggleDone = (id) => {
    console.log(id);
}

  return (
    <div className="App">
        <Todos todos={state.todos} toggleDone={toggleDone}/>
    </div>
  );
}

我想要的更新后的 state:

const App = () => {

  const [state, setState] = useState({
    todos: 
    [
        {
          id: 1,
          title: 'take out trash',
          done: false
        },
        {
          id: 2,
          title: 'wife to dinner',
          done: false
        },
        {
          id: 3,
          title: 'make react app',
          done: true // if I checked this checkbox.
        },
    ]
  })

您可以安全地使用 javascript 的數組 map 功能,因為它不會修改現有的 state,它的反應不喜歡,它會返回一個新數組。 該過程是循環遍歷狀態的數組並找到正確的 id。 更新done的 boolean。 然后使用更新的列表設置 state。

const toggleDone = (id) => {
  console.log(id);

  // loop over the todos list and find the provided id.
  let updatedList = state.todos.map(item => 
    {
      if (item.id == id){
        return {...item, done: !item.done}; //gets everything that was already in item, and updates "done"
      }
      return item; // else return unmodified item 
    });

  setState({todos: updatedList}); // set state to new object with updated list
}

編輯:更新代碼以切換item.done而不是將其設置為 true。

您需要像這樣使用擴展運算符

const toggleDone = (id) => {
    let newState = [...state];
    newState[index].done = true;
    setState(newState])
}

D. Smith 的回答很棒,但可以重構為更具聲明性,就像這樣..

const toggleDone = (id) => {
 console.log(id);
 setState(state => {
     // loop over the todos list and find the provided id.
     return state.todos.map(item => {
         //gets everything that was already in item, and updates "done" 
         //else returns unmodified item
         return item.id === id ? {...item, done: !item.done} : item
     })
 }); // set state to new object with updated list
}
const toggleDone = (id) => {
    console.log(id);
    // copy old state
    const newState = {...state, todos: [...state.todos]};
    // change value
    const matchingIndex = newState.todos.findIndex((item) => item.id == id);
    if (matchingIndex !== -1) {
       newState.todos[matchingIndex] = {
           ...newState.todos[matchingIndex], 
           done: !newState.todos[matchingIndex].done 
       }
    }
    // set new state
    setState(newState);
}

所有很好的答案,但我會這樣做

setState(prevState => {
    ...prevState,
    todos: [...prevState.todos, newObj]
})

這將安全地更新 state。 也將保持數據完整性。 這也將解決更新時的數據一致性。

如果您想做任何條件,請這樣做

setState(prevState => {
    if(condition){
        return {
            ...prevState,
            todos: [...prevState.todos, newObj]
        }
    }else{
        return prevState
    }
})

類似於D. Smith 的回答,但更簡潔一些:

const toggleDone = (id) => {

  setState(prevState => {
            // Loop over your list
            return prevState.map((item) => {
                // Check for the item with the specified id and update it
                return item.id === id ? {...item, done: !item.done} : item
            })
        })
}

我將使用 useState 而不是另一個 state 創建 todos 數組,關鍵是創建 todos 數組的副本,更新它,並將其設置為新數組。 這是一個工作示例: https://codesandbox.io/s/competent-bogdan-kn22e?file=/src/App.js

const App = () => {
  const [todos, setTodos] = useState([
    {
      id: 1,
      title: "take out trash",
      done: false
    },
    {
      id: 2,
      title: "wife to dinner",
      done: false
    },
    {
      id: 3,
      title: "make react app",
      done: false
    }
  ]);

  const toggleDone = (e, item) => {
    const indexToUpdate = todos.findIndex((todo) => todo.id === item.id);
    const updatedTodos = [...todos]; // creates a copy of the array

    updatedTodos[indexToUpdate].done = !item.done;
    setTodos(updatedTodos);
  };

暫無
暫無

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

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