React - “localStorage is not defined” error showing
Asked Answered
E

7

66

I am trying to make my website SEO friendly with meta tags. I am implementing server-side rendering in my application. After this, I am getting the following error:

ReferenceError: localStorage is not defined.

Please help how to resolve it.

My package.json:

{


 "main": "server.js",
 "scripts": {
  "start-dev": "NODE_ENV=development webpack -w & NODE_ENV=development node server.js",
  "test": "echo \"Error: no test specified\" && exit 1"
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "dependencies": {
  "axios": "^0.18.0",
  "express": "^4.15.3",
  "firebase": "^4.12.1",
  "html2canvas": "^1.0.0-alpha.12",
  "react": "^16.2.0",
  "react-adsense": "0.0.5",
  "react-dom": "^16.2.0",
  "react-facebook-login": "^4.0.1",
  "react-google-login": "^3.2.1",
  "react-meta-tags": "^0.3.0",
  "react-router-dom": "^4.2.2",
  "react-router-match-as-promised": "^1.0.5",
  "react-scripts": "1.1.1",
  "react-share": "^2.1.1",
  "react-slick": "^0.22.3"
 },
 "devDependencies": {
  "autoprefixer": "^7.1.2",
  "babel-core": "^6.25.0",
  "babel-loader": "^7.1.1",
  "babel-preset-es2015": "^6.24.1",
  "babel-preset-react-app": "^3.1.2",
  "babel-preset-stage-0": "^6.24.1",
  "css-loader": "^0.28.4",
  "extract-text-webpack-plugin": "^2.1.2",
  "file-loader": "^0.11.2",
  "postcss-loader": "^2.0.6",
  "webpack": "^3.1.0",
  "webpack-node-externals": "^1.7.2"
 }
}

Meta Tags commonly used in all pages. Home.js

<code>
import React, { Component } from 'react';
import axinst from '../common';
import {TabBox,TabBox2,TabBox3} from '../common/tabbox';
import Ads  from '../common/ads';
import SubscribeFrm from '../common/subscribefrm';
import MetaTags from 'react-meta-tags';
import AdSense from 'react-adsense';
import Loader from '../common/loader';

class Home extends Component {
  constructor(props) {
    super(props);
  }

  state = {
    header:[],
    otherSports:[],
    wizztalk:[],
    sports:[],
    isProgress:'',
    activeCat: '',
    metaTitle:'',
    metaDesc:'',
    metaKey:''
  }

  componentDidMount(){


    // axinst.get('/home')
    this.setState({isProgress:true});
    axinst.get('/home').then(response => {
      this.setState({isProgress:false});
      const header = response.data.data.Header;
      const sports = response.data.data.Sports;
      const otherSports = response.data.data.OtherSports;
      const wizztalk = response.data.data.Wizztalk;
      const metaTitle = response.data.data.metaTitle;
      const metaDesc = response.data.data.metaDesc;
      const metaKey = response.data.data.metaKeyword;
      this.setState({header});
      this.setState({sports});
      this.setState({otherSports})
      this.setState({wizztalk});
      this.setState({metaTitle});
      this.setState({metaDesc});
      this.setState({metaKey});
    }).catch(function (error) {
      // console.log(error);
      // console.log('error');
    });
  }

  render() {
    const hD = this.state.header;
    const sport = this.state.sports;
    return (
    <div id="maincontent">
        <MetaTags>
          <title>{this.state.metaTitle}</title>
          <meta name="title" content={this.state.metaTitle} />
          <meta name="keywords" content={this.state.metaKeyword} />
          <meta name="description" content={this.state.metaDesc} />
          <meta name="og:description" content={this.state.metaDesc} />
          <meta name="og:title" content={this.state.metaTitle} />
          <meta name="og:image" content={process.env.PUBLIC_URL +"/images/logo.png"}/>
        </MetaTags>
</code>
Esterify answered 24/9, 2018 at 7:7 Comment(3)
so you're trying to using localStorage on server side, right?Tahsildar
Please check my package.json file and let me know what else you need to seeEsterify
yes, Alex you are right.Esterify
M
92

When you're rendering on the server, you do not have a browser and thus you do not have access to all the APIs that the browser provides, including localStorage.

In JavaScript code that is running both on the server and on the client (browser), it is common practice to guard against with an if clause that checks if window is defined. “Window” is the root object provided by the browser for all the APIs that are provided by the browser.

Example:

if (typeof window !== 'undefined') {
    console.log('we are running on the client')
} else {
    console.log('we are running on the server');
}

In your case, you want to put your call to localStorage in such an if clause, for example:

if (typeof window !== 'undefined') {
    localStorage.setItem('myCat', 'Tom');
}
Mews answered 24/9, 2018 at 7:20 Comment(5)
The code in your question does not use localStorage anywhere. Perhaps it is used in one of the packages you're importing, possibly react-adsense. But you didn't include the part where you actually use that, so I cannot help you further.Mews
can you please guide me how to use localstorage in my application. or send any useful link if you have any.Esterify
I already did, or tried to: wherever you use local storage, check if it's actually available with an if clause like I showed in my code examplesMews
I have used your code, but still getting same error.Esterify
As @PatrickHund said you might want to check the code/docs of your dependencies to check which package is using localStorage and replace it with a SSR friendly packageTestes
T
21

This oneliner did it for me:

const checkout = typeof window !== 'undefined' ? localStorage.getItem('checkout') : null
Tip answered 6/11, 2020 at 20:47 Comment(0)
T
4

You can add a polyfill to your app. I.e. somewhere in your index.js:

if (!window) {
    require('localstorage-polyfill');
}
Tahsildar answered 24/9, 2018 at 8:19 Comment(4)
After using this code my whole code is break. --------------------- Following error is coming. Warning: Invalid DOM property class. Did you mean className?Esterify
It's not clear how it could be linked, however yes, react uses className attribute instead of class.Tahsildar
I have used this package for metatags. npmjs.com/package/react-meta-tags. i want to make it seo friendly.Esterify
it's already different issue, so I'm assuming the one you asked for help already fixed. For the last issue you've asked - just replace class with className, it should help. However, I'd note that moving everything to server side rendering - is not a simple task, you'll probably faced with other issues as well. I'd suggest you to ask new specific questions for that (of course if they hasn't been asked before). I don't think somebody here can fix everything in your app in one answer.Tahsildar
S
2

On Component you can use useEffect hook for waiting the full page load.

    useEffect(() => {
      localStorage.getItem('key');
    }, [input]);

And for hooks or functions you can use if condition to check window is loaded or not like this -

    if(window !== 'undefined'){ 
      localStorage.getItem('key')
    }
Sortilege answered 2/5, 2023 at 11:9 Comment(1)
This is correct. useEffct will load only if the client component is rendered, so for the best practices, we get localStorage in the useEffect and use useState to store the storage values.Ganglion
H
1

In my case I used a useEffect to wait for the page to load before using localStorage.

Halflife answered 23/9, 2022 at 0:11 Comment(0)
S
0

This is a more reliable approach if the component logic absolutely depends on the value of lsVar to conditionally render something.

    const Component = () => {
        if (typeof window === "undefined") return null;

        const lsVar = localStorage.getItem("lsVar");

        // component logic
        
        return (<></>);
    }
Siblee answered 3/12, 2022 at 12:30 Comment(0)
A
0

I faced this issue with NextJs while checking the query param values for session creation.

The best working solution was :

if (typeof window !== 'undefined') {
    console.log('Currently on Client side')
} else {
    console.log('Currently on Server Side');
}

Inside of the first check (Client side), simply put all the code to handle localStorage. This works for me fine.

Avebury answered 6/7, 2023 at 8:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.