CodingNic

Client State and Rendering

Load the Initial Data into Context

Client State and Rendering 18 min read

Load the Initial Data into Context

Open client/src/context/BudgetContext.jsx and find the refresh function.

The context is the right place to perform the initial read because every page needs the same transactions and categories. Loading them once here prevents each page from making duplicate requests.

Use one request for each collection and wait for both together:

javascript
const [tx, cats] = await Promise.all([
  api.getTransactions(),
  api.getCategories(),
]);

setTransactions(tx);
setCategories(cats);

Why Promise.all() is useful here

The transaction request does not depend on the category request, and the category request does not depend on the transaction request. There is therefore no reason to wait for one to finish before starting the other.

Promise.all() starts both operations and gives us both results when both succeed.

If either request fails, the catch block in refresh handles the failure and the context does not pretend that the load succeeded.

The surrounding function should keep this shape:

javascript
const refresh = useCallback(async () => {
  setLoading(true);
  setError(null);

  try {
    // load both collections here
  } catch (err) {
    setError(err.message || "Could not reach the server");
  } finally {
    setLoading(false);
  }
}, []);

setLoading(true) tells the UI a read is in progress. setError(null) clears an old error before a retry. finally runs whether the requests succeed or fail, so the interface cannot remain stuck in a loading state.

Test it

Reload the Ledger and verify that the sample transactions and categories appear.

Then open the browser Network panel and confirm there is one request to /api/transactions and one request to /api/categories during the initial load.

Checkpoint

The application has one shared initial-load operation, both collections are stored in context, and the client knows when that operation starts and finishes.