Back to Blog
Lesson 7 of the Intermediate React: Hooks, State & Data Patterns course
ReactJune 25, 20264 min read

Refactoring Dashboard Settings: Persistence with React Hooks

Learn to integrate custom hooks to manage dashboard settings. Discover how to use persistence to keep user theme preferences across page reloads in React.

ReactHooksPersistenceDashboardRefactoringFrontendjavascript

Previously in this course, we explored the mechanics of building reusable abstractions in Introduction to Custom Hooks: Master Abstraction in React and implemented a robust storage utility in Building a useLocalStorage Hook: Persistence & State Management.

In this lesson, we are moving from theory to application. We will take our useLocalStorage hook and integrate it directly into our dashboard project. By the end of this session, your dashboard will remember user theme preferences even after a browser refresh, transforming your app from a transient state container into a persistent, user-aware interface.

Why Persistence Matters for Your Dashboard

In a production-grade dashboard, user experience is defined by continuity. If a user sets their interface to "Dark Mode" to save their eyes during a late-night session, they expect that preference to be there when they return the next morning.

Without persistence, your application state lives entirely in memory. Every time the user refreshes the page or navigates away and back, that state resets to the initial value. By leveraging the browser's localStorage API, we bridge the gap between the stateless nature of React and the user's desire for a consistent environment.

Integrating the Hook: A Practical Refactor

Let's look at a typical Settings component. Before refactoring, it likely uses standard useState, which is volatile.

JSX
// Before: Volatile state
import { useState } from CE9178">'react';

const Settings = () => {
  const [theme, setTheme] = useState(CE9178">'light');

  return (
    <div>
      <label>
        Theme:
        <select value={theme} onChange={(e) => setTheme(e.target.value)}>
          <option value="light">Light</option>
          <option value="dark">Dark</option>
        </select>
      </label>
    </div>
  );
};

To make this persistent, we swap useState for our custom useLocalStorage hook. If you haven't built the hook yet, review Building a useLocalStorage Hook: Persistence & State Management to ensure you have a version that handles JSON serialization and state synchronization.

JSX
// After: Persistent state
import { useLocalStorage } from CE9178">'../hooks/useLocalStorage';

const Settings = () => {
  // We use our custom hook just like useState
  const [theme, setTheme] = useLocalStorage(CE9178">'dashboard-theme', CE9178">'light');

  return (
    <div className="settings-panel">
      <h2>Preferences</h2>
      <label htmlFor="theme-select">Interface Theme:</label>
      <select 
        id="theme-select"
        value={theme} 
        onChange={(e) => setTheme(e.target.value)}
      >
        <option value="light">Light</option>
        <option value="dark">Dark</option>
      </select>
      <p>Current theme stored: {theme}</p>
    </div>
  );
};

By changing one line of code, we've offloaded the responsibility of synchronization to our custom hook. The component remains clean, declarative, and focused solely on UI rendering.

Hands-on Exercise: Syncing the Dashboard Layout

Now it is your turn to apply this to our running project. Follow these steps to persist your dashboard's sidebar collapse state:

  1. Locate your Sidebar component.
  2. If you are currently using useState to track whether the sidebar is collapsed or expanded, replace it with useLocalStorage('sidebar-collapsed', false).
  3. Verify that when you refresh the browser while the sidebar is collapsed, it remains collapsed upon reload.
  4. Open the browser's Application tab in DevTools to confirm the sidebar-collapsed key is present in localStorage.

Common Pitfalls in State Persistence

Even with a robust hook, there are traps that catch many intermediate developers:

  • JSON Serialization Errors: localStorage only stores strings. If you try to store an object or array without JSON.stringify, you'll end up with [object Object] in your storage. Ensure your useLocalStorage hook handles this conversion internally.
  • The "Flash" of Default State: If your initialization logic is slow, the UI might render the default value before the hook reads from storage. Keep your initial value logic synchronous and performant.
  • Over-persistence: Do not store everything. Large datasets or sensitive information (like unencrypted auth tokens) should not live in localStorage. Use it only for UI preferences and non-sensitive view settings.
  • Stale Data: If you change the shape of your stored data (e.g., renaming a property), older browsers might still have the old format in their storage. Always write your code to handle potential schema mismatches gracefully.

Recap

By refactoring your dashboard settings, you’ve moved beyond simple React state into building features that feel "real" to the user. We’ve successfully:

  1. Replaced volatile useState with a persistent useLocalStorage hook.
  2. Maintained clean component logic by keeping the storage complexity hidden.
  3. Ensured that user preferences survive browser reloads.

Persistence is a foundational pillar of high-quality web applications. You now have the tools to ensure your dashboard respects the user's choices across their entire session lifecycle.

Up next: We will tackle more complex state patterns by learning to manage multiple state transitions in a single, predictable flow with useReducer.

Similar Posts