skip to Main Content

I have a problem with updating my object in array.

const [list, setList] = useState([]);

const changeRecordIndex = list.findIndex((recordItem) => recordItem.id === recordID);

I creat new array, copy object wich i need and then change one parametr of object. It’s look like great! But in this case i have a problem with final array – i have 2 similar objects with differen paramet wich i’m tring to change.

setList([...list, { ...list[changeRecordIndex], taskText: liItem.innerText }]);

In this case everything is ok

const newArr = [...list];
newArr[changeRecordIndex] = { ...newArr[changeRecordIndex], taskText: liItem.innerText };
setList(newArr);
 

What’s wrong with first case?

3

Answers


  1. The problem with your first approach is that you’re adding the updated object to the array without removing the old one, so you end up with two objects: the original and the updated one.

    In your first case:

    setList([...list, { ...list[changeRecordIndex], taskText: liItem.innerText }]);
    

    This adds all existing items from list, including the one you’re trying to update, and then adds the updated object to the end. This creates a duplicate.
    Correct approach (second case):

    const newArr = [...list];  // Copy the array
    newArr[changeRecordIndex] = { ...newArr[changeRecordIndex], taskText: liItem.innerText };  // Update the object
    setList(newArr);  // Set the updated array
    

    In this approach, you’re replacing the object in the array without duplicating it. Stick with the second method to avoid duplicates!

    Login or Signup to reply.
  2. Use Array.map() to iterate the state, and when you encounter the item you want to update, return a new item. For the rest just return the existing item. Array.map() also returns a new array, so you’re shallow cloning the array, and the changed item at once.

    In addition, when you want to update the previous state instead of replacing it, pass an updater function when you’re setting the state. The updater function is called with the previous state.

    setList(prevList => prevList.map(recordItem => 
      recordItem.id === recordID
      ? { ...recordItem, taskText: liItem.innerText }
      : recordItem
    ));
    

    A newer option is to use Array.toSpliced(), which can remove/add items at a specific index:

    setList(prevList => {
      const changeRecordIndex = list.findIndex(
        recordItem => recordItem.id === recordID
      );
      
      return prevList.toSpliced(changeRecordIndex, 1, {
        ...prevList[changeRecordIndex], 
        taskText: liItem.innerText 
      });
    });
    
    Login or Signup to reply.
  3. As Andy said above, the issue with your code is that you’re not removing the old object from the array.
    Another alternative (more concise, in my opinion) would be to use the Array’s toSpliced() method, like so:

        const newRecord = { ...list[changeRecordIndex], taskText: liItem.innerText };
    
        const newArr = list.toSpliced(changeRecordIndex, 1, newRecord);
    
        setList(newArr);
    

    P.S.: make sure to guard against findIndex()‘s possible negative result (-1)

        if(changeRecordIndex < 0) {
            // "fail fast" here
        }
        // else, update your state
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search