CodingNic

Architecture and Data

Make the Selected Month Shared State

Architecture and Data 15 min read

Make the Selected Month Shared State

Open client/src/context/BudgetContext.jsx.

The Ledger has one piece of UI state that multiple parts of the application need: the selected month. In the starter it is stored with the transaction and category collections inside the budget context:

javascript
const [transactions, setTransactions] = useState([]);
const [categories, setCategories] = useState([]);
const [cursor, setCursor] = useLocalStorage("ledger:cursor", {
  year: 2026,
  month: 8,
});

useLocalStorage behaves like React’s useState, but it also writes the value to the browser’s local storage. That means the selected month can survive a page refresh.

Why the cursor belongs here

LedgerPage needs the selected month to show the correct entries. Other pages can also need it later. Putting the cursor in the shared context prevents each page from creating its own independent month value.

The context exposes the value through its value object:

javascript
const value = {
  transactions,
  categories,
  cursor,
  setCursor,
  // other shared actions...
};

Any component inside BudgetProvider can call useBudget() and receive the same cursor.

Make month changes predictable

Find the shiftMonth function. Replace its manual month-boundary logic with JavaScript’s date arithmetic:

javascript
function shiftMonth(delta) {
  setCursor((current) => {
    const date = new Date(current.year, current.month + delta, 1);
    return { year: date.getFullYear(), month: date.getMonth() };
  });
}

Here is what the code does:

  • current.year and current.month describe the currently selected month.
  • new Date(current.year, current.month + delta, 1) moves forward or backward by delta months.
  • JavaScript automatically handles crossing from December to January or January to December.
  • The function stores the resulting year and zero-based month back in cursor.

For example, moving one month forward from December 2026 creates January 2027 automatically.

Test it

Use the left and right month controls in the Ledger.

Move from September to August, then back to September. Also test December → January and January → December by navigating far enough to cross the year boundary.

Refresh the browser and confirm that the selected month is still the month you were viewing.

Checkpoint

The selected month has one shared source of truth, month navigation works across year boundaries, and the selected month survives a refresh.