'In reactjs and nextjs constructor getting Reference Error: localstorage is not defined

i make system jsonwebtoken in reactjs and use nextjs. i find problem when i run the code in browser that is localStorage is not defined.

this is my code in file AuthStudentContext.js

import React from 'react'
import axios from 'axios'

const axiosReq = axios.create()
const AuthStudentContext = React.createContext()

export class AuthStudentContextProvider extends React.Component {

    constructor() {
        super()
        this.state = {
            students: [],
            student: localStorage.getItem('student') || {},
            token: localStorage.getItem('token') || "",
            isLoggedIn: (localStorage.getItem('student' == null)) ? false : true
        }
    }

    login = (credentials) => {
        return axiosReq.post("http://localhost:4000/api/login", credentials)
            .then(response => {
                const { token } = response.data
                localStorage.setItem("token", token)

                this.setState({
                    token,
                    isLoggedIn: true
                })

                return console.log(response)
            })
    }

and show error localStorage is not defined



Solution 1:[1]

On the constructor as well as componentWillMount lifecycle hooks, the server is still rendering the component. On the other hand, localStorage exists as part of the browser's Window global, thus you can only use it when the component is rendered. Therefore you can only access localStorage on the componentDidMount lifecycle hook. Instead of calling localStorage on the constructor, you can define an empty state, and update the state on componentDidMount when you can start to call localStorage.

constructor() { 
  super()
  this.state = {
    students: [],
    student: undefined
    token: undefined,
    isLoggedIn: undefined
  };
}

componentDidMount() {
  this.login();
  this.setState({
    student: localStorage.getItem('student') || {},
    token: localStorage.getItem('token') || "",
    isLoggedIn: (localStorage.getItem('student' == null)) ? false : true
  });
}

Solution 2:[2]

As everyone already mentioned, NextJS runs both on client and server. On the server, there is no localStorage, hence the undefined error.

However, an alternative solution is to check if nextjs is running on the server before accessing the localStorage. ie

const ISSERVER = typeof window === "undefined";

if(!ISSERVER) {
 // Access localStorage
 ...localStorage.get...
}

Solution 3:[3]

I never touched nextjs but i guess its equivalent to Nuxt.js. So it does server side rendering while you try to access localstorage on the client side.

You will need to use componentDidMount() for this. Here an example

componentDidMount(){
   localStorage.setItem('myCat', 'Tom');
   alert("Tom is in the localStorage");
}

EDIT:

Otherwise you could try with process.browser

if (process.browser) {
   localStorage.setItem("token", token);
}

Solution 4:[4]

In addition to what @SILENT said, this works for me

 React.useEffect(() => {
    if (localStorage) {
      const getLocalState = localStorage.getItem("headless");
      console.log("LocalState: ", getLocalState)
    }
  }, []);

Solution 5:[5]

Window object and Localstorage won't be available when Nextjs is building. So you need to check if the code is running in the browser. If you are running in React hooks you don't need to do this because hooks are always running browser side in React.

Just add these two utility functions to your nextjs project.

export const isBrowser = (): boolean => {
  return typeof window !== 'undefined'
}

export const nextLocalStorage = (): Storage | void => {
  if (isBrowser()) {
    return window.localStorage
  }
}

then you can use it in your code like this

nextLocalStorage()?.setItem('user', JSON.stringify(user))

Solution 6:[6]

I needed to read a token from localStorage in NextJS and add it to an axios instance header. It was outside of the component, so I used IIFE practice to ensure being in client:

(function(){
  if(typeof window !== "undefined"){
    AxiosInstance.defaults.headers.common.Authorization = `Bearer ${localStorage.getItem('TOKEN_KEY')}`
  }
})()

Solution 7:[7]

I have created a function getLocalStorageItem and called this in useEffect with the required key name. After getting the value from localStorage, saved it in a state(i.e currentUser) and used it in initialState.

 const [currentUser, setCurrentUser] = useState({});

  const getLocalStorageItem = (key) => {
    return typeof window !== undefined
      ? window.localStorage.getItem(key)
      : null;
  };

  useEffect(() => {
    setCurrentUser({
      token: getLocalStorageItem("token"),
      refreshToken: getLocalStorageItem("refreshToken"),
    });
  }, []);

  const initialState = {
    auth: {
      isLoggedIn: true,
      currentUser: currentUser,
    },
  };

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 wentjun
Solution 2 SILENT
Solution 3
Solution 4 Smart Samuel
Solution 5 Richard Torcato
Solution 6 Ali Askari
Solution 7 Azad Ansari