Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →To keep reducer-managed state after a refresh in the same tab session, initialize useReducer from sessionStorage and save committed state in a React Effect. React state remains the live source for rendering; storage is a best-effort persistence layer. The pattern below handles unavailable storage and invalid JSON, then explains how to adapt it for server-rendered apps.
Client-only implementation
Use the lazy initializer form of useReducer so the saved value is read when the component initializes, rather than on every render. Keep the reducer pure, and use an Effect to synchronize each committed state with the browser’s storage API.
import { useEffect, useReducer } from 'react';
const STORAGE_KEY = 'checkout-state';
const initialState = { step: 0, email: '' };
function reducer(state, action) {
switch (action.type) {
case 'set-email':
return { ...state, email: action.email };
case 'next-step':
return { ...state, step: state.step + 1 };
case 'reset':
return initialState;
default:
return state;
}
}
function loadInitialState() {
try {
const saved = window.sessionStorage.getItem(STORAGE_KEY);
return saved === null ? initialState : { ...initialState, ...JSON.parse(saved) };
} catch {
// Storage may be blocked, inaccessible, or contain invalid JSON.
return initialState;
}
}
function Checkout() {
const [state, dispatch] = useReducer(reducer, undefined, loadInitialState);
useEffect(() => {
try {
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch {
// Rendering and reducer updates still work without persistence.
}
}, [state]);
return <CheckoutForm state={state} dispatch={dispatch} />;
}
The third argument to useReducer is an initializer function; React uses its return value as the starting state. React’s useReducer reference describes this lazy-initialization pattern. Use getItem and setItem for storage access: Web Storage values are strings, so structured state must be serialized and parsed, commonly with JSON.stringify and JSON.parse. MDN’s Web Storage API reference also notes that the API is synchronous, which is another reason to keep saved state small.
Validate saved data before trusting it
The merge in the example restores known defaults when a saved object omits a field, but it is not full validation. A parseable value can still have the wrong type or contain unexpected fields. Validate the parsed value against the state shape before using it. When an application changes its state schema, decide whether to discard old data, migrate it, or store a version alongside it; the right choice depends on the application.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Storage is optional
Reading or writing sessionStorage can fail, including when browser policy blocks persistence or access raises a SecurityError. The example catches errors in both places, so the component can continue using in-memory React state if persistence is unavailable. MDN’s sessionStorage reference documents its access restrictions.
Keep storage out of the reducer
A reducer should calculate the next state from the current state and action; it should not read or write browser storage. The Effect is appropriate here because saving is synchronization with an external system. React’s useEffect reference puts the boundary plainly: “If you’re not trying to synchronize with some external system, you probably don’t need an Effect.”
In development, Strict Mode may call reducer and initializer functions extra times to help reveal impure logic. Keep both functions deterministic and safe to call more than once. The storage write runs in an Effect after a commit, not during reducer execution. Because Effects run after the commit, an unusual immediate reload could happen before a deferred write; if that risk matters for a particular workflow, consider a persistence abstraction or an explicit write at the action boundary while keeping reducer transitions deterministic.
What sessionStorage preserves
sessionStorage is partitioned by origin and browser tab. It survives reloads and restores within that tab session, and the session ends when the tab or window is closed. A newly opened tab normally has a separate session, although a page opened with an opener can initially receive a copy of the opener’s session storage. These behaviors are described in MDN’s sessionStorage reference.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
| Storage | Lifetime | Scope |
|---|---|---|
sessionStorage |
For the tab’s page session; ends when the tab or window closes. | Origin and tab. |
localStorage |
Persists beyond a tab session, including browser restarts, subject to browser policy and user actions. | Origin-shared rather than isolated to one tab. |
Choose sessionStorage for state that should survive refreshes during a tab session. Choose localStorage when the intended lifetime should extend beyond closing and reopening the browser. Use an app-specific key, particularly where multiple workflows share an origin, and clear persisted data when the user-visible workflow ends if that is part of the design. Do not treat browser storage as a secure vault: store only information the application is comfortable exposing to same-origin client code.
Server rendering and hydration
The lazy initializer above reads window, so it is suitable only when the component is guaranteed to render in a browser. sessionStorage does not exist on the server. In a server-rendered app, reading it during the client’s first render can produce different output from the server HTML. React requires the initial client output to match the server output for hydration; its hydrateRoot reference identifies browser-only APIs and environment-dependent rendering as common mismatch sources.
Rank #4
Restore after hydration
One approach is to render the same fallback state on the server and on the client’s first render, then read storage in a client Effect and dispatch a restore action. This avoids making the initial markup depend on browser-only data, but the fallback may appear briefly before the restored state is applied.
Render the storage-dependent UI only in the browser
Another approach is to put the storage-dependent component behind an explicitly client-only boundary with an appropriate fallback. Current React APIs document using use(browser()) for a component that renders only in the browser; server rendering requires a Suspense boundary. Confirm that the framework and React version in your app support this approach. Avoid casually using typeof window to render different initial markup on the server and client.
Best Value
Reset and key-management choices
In the example, dispatching reset returns the default state, and the Effect then writes those defaults to storage. If reset is meant to remove the saved entry instead, handle key removal explicitly in the persistence layer rather than changing reducer purity. Choose a key that distinguishes the app’s relevant workflows or users when they can share the same origin and tab.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




