Module 8: Updating State with Lists

Now let's combine everything we've learned to manage a list of items. We'll build the logic for deleting and updating items in our future Todo app.

1. The Golden Rule: State is Immutable 🏛️

Before we write any code, we must understand a core principle in React: **you should never modify state directly**. This is called "immutability".

Instead of changing the original state array (e.g., by using methods like `.push()` or `.splice()`), you must always create a **new array** with the updated data and pass that new array to your state setter function (e.g., `setTodos`).

Incorrect (Mutation): `todos.push(newTodo); setTodos(todos);` ❌
Correct (Immutable): `const newTodos = [...todos, newTodo]; setTodos(newTodos);` ✅

This rule helps React track changes efficiently and prevents subtle bugs in your application.

2. Deleting an Item from State

To delete an item, we'll use the JavaScript .filter() method. This method is perfect for immutability because it **returns a new array** containing only the items that pass a certain test.

Our event handler will receive the `id` of the todo to delete. We will then filter the `todos` array, keeping every todo *except* the one with the matching `id`.


const { useState } = React;

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Item 1', completed: false },
    { id: 2, text: 'Item 2', completed: false },
    { id: 3, text: 'Item 3', completed: false },
  ]);

  const handleDelete = (idToDelete) => {
    // Create a new array that excludes the item with the matching id
    const newTodos = todos.filter(todo => todo.id !== idToDelete);
    
    // Update the state with this new array
    setTodos(newTodos);
  };

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>
          {todo.text}
          {/* We use an inline arrow function to pass the id */}
          <button onClick={() => handleDelete(todo.id)}>Delete</button>
        </li>
      ))}
    </ul>
  );
}

3. Updating an Item in State

To update an item (like toggling its `completed` status), we'll use the JavaScript .map() method. This method also **returns a new array**, making it ideal for immutable updates.

We will map over the original `todos` array. For each todo, we'll check if it's the one we want to update.

  • If it is, we return a **new object** with the changed property.
  • If it's not, we return the original, unchanged todo object.


// (Inside the same TodoList component)

const handleToggleComplete = (idToToggle) => {
  const newTodos = todos.map(todo => {
    // If this is the todo we're looking for...
    if (todo.id === idToToggle) {
      // ...return a new object with the 'completed' property flipped
      return { ...todo, completed: !todo.completed };
    }
    // Otherwise, return the original todo
    return todo;
  });

  setTodos(newTodos);
};