After a login, the storefront keeps the user in React state, in the AuthProvider. But a reload runs the app from the start. Every useState begins again, so user is null and the header forgets who is there.
The login is not lost, though. The browser still has the session cookie, and it sends it with every request to the API. So the app can ask the server: GET /api/me answers with the session's user, or 401 when nobody is logged in.
An effect with an empty list [] runs once, when the component starts. Here is one that loads the products once:
useEffect(() => {
async function loadProducts() {
try {
const data = await api("/api/products");
setProducts(data);
} catch (err) {
setMessage(err.message);
} finally {
setWaiting(false);
}
}
loadProducts();
}, []);
api() throws when the answer is not OK, so a 401 lands in the catch. The finally runs after any answer, good or bad: that is where the waiting ends. Until then, loading is true, and the header shows neither the email nor the Log in link.
The check opens the login page, logs in as Ana, reloads, and expects:
open /login → GET /api/me → 401 header: Products, Sign up, Log in log in as Ana → header: Logged in as ana@example.com reload the page → GET /api/me → 200 header: Logged in as ana@example.com
Your task: in client/src/AuthContext.jsx, make the provider ask /api/me once at the start, keep the user it answers (or null when nobody is logged in), and set loading to false once the answer is in.
Assignment
Follow the Coding Tutorial to fill in loadUser, call it from the effect, and end the loading in the finally.
Hint
The browser sends the cookie by itself: await api("/api/me") is all the request needs. The catch means nobody is logged in; the finally runs after either answer.
Free plan: 30 tutor messages. PRO is unlimited.
