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 insideuseState
to initialize the state with the value fromlocalStorage
(if it exists).useEffect
Hook: The effect hook ensures that whenever thetheme
state changes, it is saved tolocalStorage
.
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: LikelocalStorage
, we usesessionStorage
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 usingJSON.stringify()
andJSON.parse()
, ensuring that non-string data can be correctly saved in the storage.