Learn to use localStorage to persist your React app's state across browser refreshes. Master the art of syncing local data with your component state.
Previously in this course, we covered handling browser history. While that lesson focused on navigation, today we are tackling the "memory" of your application: how to keep data alive even after a user refreshes the page.
React state is volatile. Every time a user refreshes their browser, your application re-initializes, and your useState values reset to their defaults. If you want to remember a user's theme preference, a draft they were typing, or a list of items they interacted with, you need a way to store that data outside of React's memory. The browser's localStorage API is the standard tool for this persistence.
localStorage is a simple key-value store built into every modern browser. It is synchronous, meaning it blocks the main thread while reading or writing, so we must use it carefully. Because it only stores strings, we have to serialize our data (using JSON.stringify) when saving it and deserialize it (using JSON.parse) when reading it back.
The primary methods you need are:
localStorage.setItem('key', 'value'): Stores data.localStorage.getItem('key'): Retrieves data.localStorage.removeItem('key'): Deletes a specific item.To make localStorage work with React, we need to bridge the gap between the browser's storage and our component's state. We do this by initializing state from storage and using useEffect to save changes whenever that state updates.
Consider a "Dark Mode" toggle for our movie browser. We want the user's choice to persist even if they close and reopen the tab.
JSXimport { useState, useEffect } from CE9178">'react'; function ThemeToggle() { // 1. Initialize state from localStorage const [isDarkMode, setIsDarkMode] = useState(() => { const savedTheme = localStorage.getItem(CE9178">'isDarkMode'); return savedTheme ? JSON.parse(savedTheme) : false; }); // 2. Sync state changes to localStorage useEffect(() => { localStorage.setItem(CE9178">'isDarkMode', JSON.stringify(isDarkMode)); }, [isDarkMode]); return ( <button onClick={() => setIsDarkMode(!isDarkMode)}> Switch to {isDarkMode ? CE9178">'Light' : CE9178">'Dark'} Mode </button> ); }
In this example, notice the "lazy initializer" function inside useState. By passing a function instead of a raw value, we ensure that localStorage.getItem only runs once during the initial mount, rather than on every single re-render. This is a crucial performance optimization for managing state.
Let's apply this to our movie project. In your existing movie browser, find the component that handles the search input.
localStorage key called 'movie-search-query'.useState hook for the search term to initialize from that key.useEffect hook that saves the search term to localStorage whenever the user types in the input.Even for experienced engineers, localStorage has a few traps:
localStorage is synchronous, don't use it for massive amounts of data (like a 50MB JSON blob). It will make your app feel stuttery.localStorage.getItem returns null (because the key doesn't exist yet), JSON.parse(null) will return null. Always provide a fallback default value (e.g., savedTheme ? JSON.parse(savedTheme) : false).localStorage. It is accessible by any script running on your page, making it vulnerable to Cross-Site Scripting (XSS) attacks.localStorage is completely external to this process. Always keep your React state as the "source of truth."Persistence is the final piece of the puzzle for a functional, user-friendly UI. We’ve learned that:
localStorage is the browser's built-in key-value storage.JSON.stringify and JSON.parse data since storage only accepts strings.useState prevents expensive storage lookups on every render.useEffect is the perfect place to synchronize our React state with the browser's persistent storage.By mastering this, you’ve ensured your users don't lose their progress when they navigate away or refresh. You're building apps that feel robust and thoughtful.
Up next: We will build a Favorites List, where we will use these persistence concepts to manage arrays of data.
Master the fetch API in React to retrieve external data. Learn to perform asynchronous requests and store JSON responses in your component state effectively.
Working with LocalStorage
Using External Libraries
Advanced