Welcome to the first step in making your game feel production-ready. Today, you will add a persistence layer so player progress survives page reloads within the same browser tab. You will build small, reliable utilities to save and load a profile and wire them into the existing GameProvider so the profile syncs automatically. This sets the foundation for the dynamic stats and polish you will add later in the course.
Before we dive in, it’s important to know that there are two main browser storage options for saving data on the client:
sessionStorage: Data is kept only as long as the browser tab is open. If you reload the page or navigate away and back in the same tab, the data is still there. But if you close the tab or browser, or open the site in a new tab, the data is gone.localStorage: Data is kept even after the browser or tab is closed and reopened. It persists across browser restarts and is shared across all tabs/windows for the same site.
In this course, we use sessionStorage for simplicity and to avoid stale data issues during development. This means your progress is saved as long as you keep the tab open. If you want your game to remember progress even after closing and reopening the browser, you can swap sessionStorage for localStorage in the code—the API is the same!
Create a dedicated module that knows how to read and write the profile safely. It includes simple versioning so you can evolve the structure later without breaking older saves.
src/utils/persistence.js
Explanation:
STORAGE_KEYidentifies where the profile is stored insessionStorage.VERSIONguards your data shape. If it changes, old data is safely ignored.loadProfilereturns a parsed profile ornullif it is missing, outdated, or broken.saveProfilewraps the profile with the version and a timestamp, then writes it.- Both functions handle errors so your app does not crash due to storage issues.
Initialize global state with any stored profile and keep it in sync whenever the profile changes. This makes saving and loading transparent to the rest of your app.
src/context/GameContext.jsx
Explanation:
- The reducer initializer runs once, calling
loadProfileto restore any progress saved in the current browser tab. - A
useEffectwatchesstate.profileand callssaveProfilewhenever it changes, keeping storage up to date automatically. GameContextprovidesstateanddispatch;useGameSelectoris a small helper for selecting slices of state.
You now have a clean persistence layer:
- A safe, versioned load/save utility for the profile.
- Automatic restore on page load (in the same tab) and automatic save on profile changes.
This reliability opens the door to richer features, like dynamic menus and lifetime stats. Ready to see it in action? Head to the practice section and solidify what you learned.
