React 5 2 Use of lists with status
We can now type a new expense in the form, but the list of expenses still ignores it. To make the page actually refresh whenever an expense is added, we need to lift the data into a piece of React state living inside App.js — that is the component that already receives the new expense through addExpenseHandler.
At the top of App, we import the useState hook from React and we turn the static expenses array into a state slice. The initial value is the same dummy array we already had.
import { useState } from 'react';
const App = () => {
const [expenses, setExpenses] = useState(DUMMY_EXPENSES);
const addExpenseHandler = (expense) => {
setExpenses((prevExpenses) => {
return [expense, ...prevExpenses];
});
};
return (/* ... */);
};
Why we pass a function to setExpenses
- The new array depends on the previous one — we need every existing expense to remain in place.
- The function form receives the most recent snapshot of state as its first argument, which we name
prevExpenses. - We return a new array starting with the freshly added
expense, followed by every previous entry thanks to the spread operator.
Putting the new entry first means it appears at the top of the list immediately after being submitted — a small but pleasant UX touch. And that's how you output a dynamic list of data with React: keep the data in state, let the JSX consume it through .map, and update the state with a setter that respects the previous snapshot. In the next lesson we tackle the key warning that React prints in the console whenever a list is rendered without a stable identifier.
Summary
This lesson covers dynamically updating expense lists in React using the useState hook. It demonstrates how to properly manage state by using the spread operator to add new expenses and explains the best practice of using a functional form when updating state based on previous values. By implementing this pattern, new expenses are automatically prepended to the list, creating a responsive and properly managed list component.
Key points
- Import useState from React to manage expense list state
- Use the spread operator (...) to copy existing expenses when adding new items
- Always use the functional form of setState when updating state based on the previous state snapshot
- The functional form receives the latest state snapshot automatically
- New expenses are added to the beginning of the list using this approach
- This pattern prevents state update bugs and ensures proper list management
FAQ
Why use a function with setState instead of passing the object directly?
When updating state based on the previous state, using a function ensures you receive the latest state snapshot automatically, preventing race conditions and stale state issues. Direct object passing can miss intermediate state updates.
What does the spread operator do in this context?
The spread operator (...) extracts all elements from the existing expenses array, allowing you to copy them into a new array with the additional expense, maintaining immutability.
Where are new expenses added in the list?
New expenses are added at the beginning of the list because the new expense is placed first, followed by the spread of existing expenses using the pattern [newExpense, ...previousExpenses].