How to Persist React Component State Across Page Reloads with Zero External Libraries
HexShift

HexShift @hexshift

About: Help with web development through niche, technical tutorials. From advanced JavaScript patterns and TypeScript best practices to mastering frameworks. Support link at base of each article. Thanks.

Joined:
Apr 5, 2025

How to Persist React Component State Across Page Reloads with Zero External Libraries

Publish Date: Apr 26
0 0

Keeping UI state after a page refresh can seriously boost user experience. But dragging in Redux Persist or localforage is often unnecessary for small to mid-sized apps. Here’s a no-library method to persist React component state across reloads using just the browser’s native capabilities.

Why Bother With State Persistence?

Use cases include:

  • Keeping form inputs intact after accidental reloads
  • Saving UI preferences like dark mode toggles
  • Storing lightweight user session data

Step 1: Build a usePersistentState Hook

This custom hook wraps useState and connects it to localStorage automatically:

// usePersistentState.js
import { useState, useEffect } from "react";

export function usePersistentState(key, defaultValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored !== null ? JSON.parse(stored) : defaultValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

Step 2: Use It in Your Components

// SettingsForm.js
import { usePersistentState } from "./usePersistentState";

function SettingsForm() {
  const [username, setUsername] = usePersistentState("username", "");
  const [theme, setTheme] = usePersistentState("theme", "light");

  return (
    <form>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="Enter your username"
      />
      <select value={theme} onChange={(e) => setTheme(e.target.value)}>
        <option value="light">Light</option>
        <option value="dark">Dark</option>
      </select>
    </form>
  );
}

export default SettingsForm;

Step 3: That's It

Now even if the user refreshes the page, the input fields and settings stick without server involvement.

Pros and Cons

✅ Pros

  • No external dependencies
  • Instant, seamless persistence for critical UI elements
  • Can be abstracted for sessionStorage, cookies, or IndexedDB if needed

⚠️ Cons

  • localStorage is synchronous — heavy writes could block the main thread (rare)
  • Data must be JSON-serializable (no functions, Dates need special handling)
  • localStorage is shared across tabs — no "tab-scoped" persistence

🚀 Alternatives

  • Redux Persist: If you're already using Redux, it handles complex state trees well.
  • Jotai + atomWithStorage: Dead-simple for smaller apps with better reactivity.

Summary

Sometimes you don't need a sledgehammer for a thumbtack. For lightweight state persistence in React, a simple hook backed by localStorage is fast, free, and robust enough for tons of real-world use cases.

For a much more extensive guide on getting the most out of React portals, check out my full 24-page PDF file on Gumroad. It's available for just $10:

Using React Portals Like a Pro.

If you found this useful, you can support me here: buymeacoffee.com/hexshift

Comments 0 total

    Add comment