How to use Session Storage in React using a Custom Hook
Jasser Mark Arioste
Hello, hustlers! In this tutorial, you'll learn how to use the browser SessionStorage API in react by using a custom hook from usehooks-ts library.
Introduction #
Sometimes, we want to persist some application states between page refreshes. One good way to do this is to use sessionStorage. However, since sessionStorage is only available in the browser, it might be tricky to implement especially if you're using server-side rendering.
In this tutorial, we use the convenient useSessionStorage hook from the usehooks-ts
library to easily access the browser sessionStorage API. It also takes care of and ensures it's safe to use.
Installing the Dependencies #
If we want to use usehooks-ts library first we have to install it. Run the following command:
# yarn
yarn add usehooks-ts
# npm
npm i usehooks-ts
How to use the useSessionStorage
hook
#
Using the useSessionStorage
hook is very similar to the useState
hook, but we have to pass in two parameters, a key, and a value. For example:
// components/Counter.tsx import { useSessionStorage } from "usehooks-ts"; const Counter = () => { const [count, setCount] = useSessionStorage("count", 0); return ( <div> Counter <button onClick={() => setCount((prev) => prev + 1)}>{count}</button> </div> ); }; export default Counter;
12345678910111213
If we click on the button, the counter increments. We can also verify the state on the application tab of the browser dev tools. If we refresh the page, we see that it's initialized to 3 instead of 0.
When to use the useSessionStorage
hook
#
It is best to use this hook if you want to do the following:
- Share a specific application state between different components. For example, themes, user settings, etc.
- Persist a specific application state between browser refresh
When not to use the useSessionStorage
hook
#
Do not use this hook if you want to use different states for the same component. In our example above, if we render multiple instances of <Counter/>
component it initializes to whatever the value of "count" in the sessionStorage
is.
I don't want to install usehooks-ts
#
Sometimes, we don't want extra dependencies on our application. You can create your own useSessionStorage
hook by using the following code (taken from the usehooks-ts
documentation):
// hooks/useSessionStorage.tsx import { Dispatch, SetStateAction, useCallback, useEffect, useState, } from 'react' import { useEventCallback, useEventListener } from 'usehooks-ts' declare global { interface WindowEventMap { 'session-storage': CustomEvent } } type SetValue<T> = Dispatch<SetStateAction<T>> function useSessionStorage<T>(key: string, initialValue: T): [T, SetValue<T>] { // Get from session storage then // parse stored json or return initialValue const readValue = useCallback((): T => { // Prevent build error "window is undefined" but keep keep working if (typeof window === 'undefined') { return initialValue } try { const item = window.sessionStorage.getItem(key) return item ? (parseJSON(item) as T) : initialValue } catch (error) { console.warn(`Error reading sessionStorage key “${key}”:`, error) return initialValue } }, [initialValue, key]) // State to store our value // Pass initial state function to useState so logic is only executed once const [storedValue, setStoredValue] = useState<T>(readValue) // Return a wrapped version of useState's setter function that ... // ... persists the new value to sessionStorage. const setValue: SetValue<T> = useEventCallback(value => { // Prevent build error "window is undefined" but keeps working if (typeof window == 'undefined') { console.warn( `Tried setting sessionStorage key “${key}” even though environment is not a client`, ) } try { // Allow value to be a function so we have the same API as useState const newValue = value instanceof Function ? value(storedValue) : value // Save to session storage window.sessionStorage.setItem(key, JSON.stringify(newValue)) // Save state setStoredValue(newValue) // We dispatch a custom event so every useSessionStorage hook are notified window.dispatchEvent(new Event('session-storage')) } catch (error) { console.warn(`Error setting sessionStorage key “${key}”:`, error) } }) useEffect(() => { setStoredValue(readValue()) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const handleStorageChange = useCallback( (event: StorageEvent | CustomEvent) => { if ((event as StorageEvent)?.key && (event as StorageEvent).key !== key) { return } setStoredValue(readValue()) }, [key, readValue], ) // this only works for other documents, not the current one useEventListener('storage', handleStorageChange) // this is a custom event, triggered in writeValueTosessionStorage // See: useSessionStorage() useEventListener('session-storage', handleStorageChange) return [storedValue, setValue] } export default useSessionStorage // A wrapper for "JSON.parse()"" to support "undefined" value function parseJSON<T>(value: string | null): T | undefined { try { return value === 'undefined' ? undefined : JSON.parse(value ?? '') } catch { console.log('parsing error on', { value }) return undefined } }
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
Full Code and Demo #
The full code and demo are available on Stackblitz: React Session Storage Tutorial.
Conclusion #
You learned how to use the sessionStorage
API in React by using the useSessionStorage
custom hook. The window.sessionStorage
object is a great way to store some state of your application and useSessionStorage
just simplifies the process.
Resources #
You might want to explore other hooks provided by the usehooks-ts
library.
Credits: Image by Ida from Pixabay