How to update an array of objects in React state
Tags: react, webdev, javascript, beginners
Published: 2022-11-15 05:18:51

Let’s go over how we can update an array of objects in React state. We have to treat React state as immutable, therefore we have to ensure we create a new copy when mutating the array.

Let’s implement`handleMarkComplete` in the following example:

```js
import { useState } from "react";

const List = () => {
  const [todos, setTodos] = useState([
    { id: 1, task: "gym", isComplete: false },
    { id: 2, task: "tan", isComplete: false },
    { id: 3, task: "laundry", isComplete: false },
  ]);
  
  const handleMarkComplete = (id) => {
    // 1. Find the todo with the provided id
    // 2. Mark the todo as complete
    // 3. Update the todo list with the updated todo
  };

  return (
    <div>
      {todos.map((todo) => (
        <div
          key={todo.id}
          onClick={() => handleMarkComplete(todo.id)}
        >
          {todo.task}
        </div>
      ))}
    </div>
  );
}
```

Let’s write our implementation without the spread operator so we understand what’s going on.

```js
const handleMarkComplete = (id) => {
  // 1. Find the todo with the provided id
  const currentTodoIndex = todos.findIndex((todo) => todo.id === id);
  // 2. Mark the todo as complete
  const updatedTodo = Object.assign({}, todos[currentTodoIndex]);
  updatedTodo.isComplete = true;
  // 3. Update the todo list with the updated todo
  const newTodos = todos.slice();
  newTodos[currentTodoIndex] = updatedTodo;
  setTodos(newTodos);
};
```

Now that we know what’s going on, let’s use the spread operator.

```js
const handleMarkComplete = (id) => {
  // 1. Find the todo with the provided id
  const currentTodoIndex = todos.findIndex((todo) => todo.id === id);
  // 2. Mark the todo as complete
  const updatedTodo = {...todos[currentTodoIndex], isComplete: true};
  // 3. Update the todo list with the updated todo
  const newTodos = [...todos];
  newTodos[currentTodoIndex] = updatedTodo;
  setTodos(newTodos);
};
```

We can refactor further by combining spread operators with slice.

```js
const handleMarkComplete = (id) => {
  // 1. Find the todo with the provided id
  const currentTodoIndex = todos.findIndex((todo) => todo.id === id);
  // 2. Mark the todo as complete
  const updatedTodo = {...todos[currentTodoIndex], isComplete: true};
  // 3. Update the todo list with the updated todo
  const newTodos = [
    ...todos.slice(0, currentTodoIndex),
    updatedTodo,
    ...todos.slice(currentTodoIndex + 1)
  ];
  setTodos(newTodos);
};
```

There is an alternate approach we can take by using the `map` function. This function might look cleaner but it’s not as efficient as our previous example because we are building up the array one item at a time.

```js
const handleMarkComplete = (id) => {
  const newTodos = todos.map((todo) => {
    if (todo.id === id) {
      return {...todo, isComplete: true};
    }
    return todo;
  });

  setTodos(newTodos);
};
```

# Conclusion

The spread operator is syntactic sugar that we should use once we understand what it does underneath the hood. If we need a refresher on how to update objects and arrays in React state, I wrote an article here: [Cheat Sheet for Updating Objects and Arrays in React State](https://dev.to/andyrewlee/cheat-sheet-for-updating-objects-and-arrays-in-react-state-48np).