ReactHustle

How to use Session Storage in React using a Custom Hook

Jasser Mark Arioste

Jasser Mark Arioste

How to use Session Storage in React using a Custom Hook

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.

React Session Storage Tutorial screenshot.

When to use the useSessionStorage hook #

It is best to use this hook if you want to do the following:

  1. Share a specific application state between different components. For example, themes, user settings, etc.
  2. 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

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle