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:
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:
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.