Table of Contents
Have you received the following error while using local storage in Next.js?
1ReferenceError: localStorage is not defined
In this article, we will see how to use local storage in Next.js
Project set up
Create a Next.js application using the following command:
1npx create-next-app next-local-storage
Update index.js
with the following code:
1import { useState } from "react"23export default function Home() {4 let value5 // Get the value from local storage if it exists6 value = localStorage.getItem("favoriteNumber") || ""78 // Set the value received from the local storage to a local state9 const [favoriteNumber, setFavoriteNumber] = useState(value)1011 // When user submits the form, save the favorite number to the local storage12 const saveToLocalStorage = e => {13 e.preventDefault()14 localStorage.setItem("favoriteNumber", favoriteNumber)15 }1617 return (18 <div>19 <label htmlFor="number">Your favorite number</label>20 <form onSubmit={saveToLocalStorage}>21 <input22 id="number"23 value={favoriteNumber}24 onChange={e => setFavoriteNumber(e.target.value)}25 />26 <input type="submit" value="Save" />27 </form>28 </div>29 )30}
Now if you run the code, you will get the following error:
Why does the error occur?
The error occurs because the code gets compiled in the server (in localhost or server-side rendering in production),
localStorage
object does not exist.
The fix
There are multiple ways in which it can be fixed.
Checking if the window is defined
localStorage
is an object inside the window
object.
The window object will not be defined in the server and hence the localStorage code will not be executed in the server.
1if (typeof window !== "undefined") {2 value = localStorage.getItem("favoriteNumber") || ""3}
Using try-catch block
We can use a try-catch block to surround the localStorage
access:
1try {2 value = localStorage.getItem("favoriteNumber") || ""3} catch (error) {}
Using a useEffect hook
You can use a useEffect hook to get the localStorage content. The useEffect hook will not be run in the server and hence no possibility of the error.
1import { useEffect, useState } from "react"23export default function Home() {4 // Set the value received from the local storage to a local state5 const [favoriteNumber, setFavoriteNumber] = useState("")67 useEffect(() => {8 let value9 // Get the value from local storage if it exists10 value = localStorage.getItem("favoriteNumber") || ""11 setFavoriteNumber(value)12 }, [])1314 // When user submits the form, save the favorite number to the local storage15 const saveToLocalStorage = e => {16 e.preventDefault()17 localStorage.setItem("favoriteNumber", favoriteNumber)18 }1920 return (21 <div>22 <label htmlFor="number">Your favorite number</label>23 <form onSubmit={saveToLocalStorage}>24 <input25 id="number"26 value={favoriteNumber}27 onChange={e => setFavoriteNumber(e.target.value)}28 />29 <input type="submit" value="Save" />30 </form>31 </div>32 )33}
Using a custom hook
You can use a custom hook to access local storage as well
1import { useState } from "react"23const useLocalStorage = (key, initialValue) => {4 const [state, setState] = useState(() => {5 // Initialize the state6 try {7 const value = window.localStorage.getItem(key)8 // Check if the local storage already has any values,9 // otherwise initialize it with the passed initialValue10 return value ? JSON.parse(value) : initialValue11 } catch (error) {12 console.log(error)13 }14 })1516 const setValue = value => {17 try {18 // If the passed value is a callback function,19 // then call it with the existing state.20 const valueToStore = value instanceof Function ? value(state) : value21 window.localStorage.setItem(key, JSON.stringify(valueToStore))22 setState(value)23 } catch (error) {24 console.log(error)25 }26 }2728 return [state, setValue]29}3031export default useLocalStorage
In index.js
, you can use it as follows:
1import useLocalStorage from "@/hooks/useLocalStorage"2import { useState } from "react"34export default function Home() {5 // Get the value from local storage if it exists6 const [value, setValue] = useLocalStorage("favoriteNumber", "")78 // Set the value received from the local storage to a local state9 const [favoriteNumber, setFavoriteNumber] = useState(value)1011 // When user submits the form, save the favorite number to the local storage12 const saveToLocalStorage = e => {13 e.preventDefault()14 setValue(favoriteNumber)15 }1617 return (18 <div>19 <label htmlFor="number">Your favorite number</label>20 <form onSubmit={saveToLocalStorage}>21 <input22 id="number"23 value={favoriteNumber}24 onChange={e => setFavoriteNumber(e.target.value)}25 />26 <input type="submit" value="Save" />27 </form>28 </div>29 )30}
Source code and Demo
You can view the complete source code here and a demo here
Do follow me on twitter where I post developer insights more often!