Implementing a Persistence Layer

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.

A Quick Note on Browser Storage: sessionStorage vs. localStorage

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!

Build Lightweight Persistence Utilities

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_KEY identifies where the profile is stored in sessionStorage.
  • VERSION guards your data shape. If it changes, old data is safely ignored.
  • loadProfile returns a parsed profile or null if it is missing, outdated, or broken.
  • saveProfile wraps 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.
Wire Persistence into GameProvider

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 loadProfile to restore any progress saved in the current browser tab.
  • A useEffect watches state.profile and calls saveProfile whenever it changes, keeping storage up to date automatically.
  • GameContext provides state and dispatch; useGameSelector is a small helper for selecting slices of state.
Recap and Next Steps

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.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal