Persisting State with LocalStorage/SessionStorage

Loading

Persisting state across page reloads or browser sessions is a common requirement in many web applications. This ensures that users don’t lose their data when they refresh the page or navigate away. LocalStorage and SessionStorage are two browser APIs that allow you to store data in the browser.

  • LocalStorage persists data across sessions, meaning it survives page reloads and browser restarts.
  • SessionStorage persists data only for the duration of the page session (i.e., until the browser tab is closed).

In React, you can leverage these APIs to store and retrieve state data. Below, we’ll explore how to use LocalStorage and SessionStorage to persist state in React applications.


1. Using LocalStorage in React

LocalStorage is used for storing data that needs to persist even after the browser is closed and reopened. It is useful for saving user preferences, authentication tokens, and other non-sensitive data that should remain across sessions.

Example: Persisting User Preferences with LocalStorage

Let’s say we want to persist a theme selection (light or dark) across page reloads.

// ThemeSwitcher.js
import React, { useState, useEffect } from 'react';

const ThemeSwitcher = () => {
  const [theme, setTheme] = useState(() => {
    // Check if theme is stored in localStorage
    const savedTheme = localStorage.getItem('theme');
    return savedTheme ? savedTheme : 'light'; // Default to 'light' if no theme is stored
  });

  useEffect(() => {
    // Save theme to localStorage whenever it changes
    localStorage.setItem('theme', theme);
  }, [theme]);

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <div className={`app ${theme}`}>
      <h1>Current Theme: {theme}</h1>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
};

export default ThemeSwitcher;

Explanation:

  • useState with Lazy Initialization: We’re using a function inside useState to initialize the state with the value from localStorage (if it exists).
  • useEffect Hook: The effect hook ensures that whenever the theme state changes, it is saved to localStorage.

2. Using SessionStorage in React

SessionStorage is ideal for temporary data that should only persist as long as the browser tab is open. Once the tab is closed, the data is cleared. This is useful for storing transient data, like user inputs in a multi-step form, or data that should not persist beyond the current session.

Example: Persisting Multi-step Form State with SessionStorage

Let’s say we want to save the form data temporarily in SessionStorage while the user is filling out a multi-step form.

// MultiStepForm.js
import React, { useState, useEffect } from 'react';

const MultiStepForm = () => {
  const [formData, setFormData] = useState(() => {
    // Retrieve saved data from sessionStorage
    const savedData = sessionStorage.getItem('formData');
    return savedData ? JSON.parse(savedData) : { name: '', email: '' };
  });

  useEffect(() => {
    // Save formData to sessionStorage whenever it changes
    sessionStorage.setItem('formData', JSON.stringify(formData));
  }, [formData]);

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevData) => ({
      ...prevData,
      [name]: value,
    }));
  };

  return (
    <div>
      <h1>Multi-step Form</h1>
      <form>
        <input
          type="text"
          name="name"
          placeholder="Name"
          value={formData.name}
          onChange={handleInputChange}
        />
        <input
          type="email"
          name="email"
          placeholder="Email"
          value={formData.email}
          onChange={handleInputChange}
        />
      </form>
    </div>
  );
};

export default MultiStepForm;

Explanation:

  • useState with Lazy Initialization: Like localStorage, we use sessionStorage in the same way to persist form data temporarily.
  • useEffect Hook: It saves the form data to SessionStorage each time the user updates the form.

3. Handling Expiry of Data in LocalStorage

Unlike SessionStorage, LocalStorage does not have a built-in expiration mechanism. If you need to set an expiration time for stored data (for example, storing an authentication token that expires after 1 hour), you’ll need to implement this logic manually.

Example: Token Expiry in LocalStorage

// Auth.js
import React, { useState, useEffect } from 'react';

const Auth = () => {
  const [token, setToken] = useState(() => {
    const storedToken = localStorage.getItem('authToken');
    const tokenExpiry = localStorage.getItem('tokenExpiry');
    
    // Check if the token has expired
    if (storedToken && tokenExpiry && new Date().getTime() < tokenExpiry) {
      return storedToken;
    }
    return null; // Token expired or doesn't exist
  });

  const login = (newToken) => {
    const expiryTime = new Date().getTime() + 60 * 60 * 1000; // 1 hour expiration
    localStorage.setItem('authToken', newToken);
    localStorage.setItem('tokenExpiry', expiryTime);
    setToken(newToken);
  };

  const logout = () => {
    localStorage.removeItem('authToken');
    localStorage.removeItem('tokenExpiry');
    setToken(null);
  };

  return (
    <div>
      {token ? (
        <div>
          <h1>Welcome, User!</h1>
          <button onClick={logout}>Logout</button>
        </div>
      ) : (
        <button onClick={() => login('new-auth-token')}>Login</button>
      )}
    </div>
  );
};

export default Auth;

Explanation:

  • Expiration Logic: We save the token expiry time (1 hour from the current time) in LocalStorage. When we load the token, we compare the current time with the expiry time to decide whether the token is still valid.

4. Handling JSON Data

Both LocalStorage and SessionStorage store data as strings. If you need to store objects, arrays, or more complex data, you’ll need to serialize it to a string using JSON.stringify() before saving and deserialize it using JSON.parse() when retrieving it.

Example: Storing and Retrieving an Object

// UserProfile.js
import React, { useState, useEffect } from 'react';

const UserProfile = () => {
  const [profile, setProfile] = useState(() => {
    const savedProfile = localStorage.getItem('profile');
    return savedProfile ? JSON.parse(savedProfile) : { name: '', age: 0 };
  });

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

  const updateProfile = (e) => {
    const { name, value } = e.target;
    setProfile((prevProfile) => ({
      ...prevProfile,
      [name]: value,
    }));
  };

  return (
    <div>
      <h1>User Profile</h1>
      <input
        type="text"
        name="name"
        value={profile.name}
        onChange={updateProfile}
      />
      <input
        type="number"
        name="age"
        value={profile.age}
        onChange={updateProfile}
      />
    </div>
  );
};

export default UserProfile;

Explanation:

  • JSON Handling: We store and retrieve the profile object using JSON.stringify() and JSON.parse(), ensuring that non-string data can be correctly saved in the storage.

Leave a Reply

Your email address will not be published. Required fields are marked *