skip to Main Content

I have a component that is supposed to be rendered on client side but I get an error in the terminal stating that it cannot read localStorage because it is undefined and that happens because the app is trying to render it on the server. Heres the code where in the first line I set rendering to be on the client side

"use client";

import Image from "next/image";
import { useState } from "react";
import chevron from "../public/icons/chevron.png";
export default function LanguageSwitch() {
    let lang: string | null = null;

    const [openMenu, setOpenMenu] = useState(false);
    lang = localStorage?.getItem("lang");

    const handleLanguage = () => {
        localStorage?.setItem('lang', lang ? lang == 'SRB' ? 'ENG' : 'SRB' : 'ENG')
    }

    return (
        <div className="language-switch" onClick={() => setOpenMenu(p => !p)} >
            <p className="menu-item">{lang ?? "SRB"}</p>
            <Image src={chevron} alt="" />
            <div>
                {openMenu && <p onClick={handleLanguage} className="menu-item language-select">
                    {lang ? (lang == "SRB" ? "ENG" : "SRB") : "ENG"}
                </p>}
            </div>
        </div>
    );
}

This is the error:

 ReferenceError: localStorage is not defined

I’m using Next.js 13.

2

Answers


  1. when a client component inside a server component, both components get rendered on the server. Where exactly is the page rendered, even with 'use client'?

    that is why you should still be adding a guard

     if (typeof window !== 'undefined' && window.localStorage) {
        // here you can access to localstorage
     }
    
    Login or Signup to reply.
  2. Client Components, with use client also render first on the server. So no browser specific API should be called in the component body. It should be only in event handlers, useEffect callbacks…

    "use client";
    
    import Image from "next/image";
    import { use, useEffect, useState } from "react";
    import chevron from "../public/icons/chevron.png";
    export default function LanguageSwitch() {
      const [lang, setLang] = useState<string | null>(null);
    
      const [openMenu, setOpenMenu] = useState(false);
      useEffect(() => {
        setLang(localStorage?.getItem("lang"));
      }, []);
    
      const handleLanguage = () => {
        localStorage?.setItem("lang", lang ? (lang == "SRB" ? "ENG" : "SRB") : "ENG");
      };
    
      if (!lang) {
        <div>Loadding...</div>;
      }
    
      return (
        <div className="language-switch" onClick={() => setOpenMenu((p) => !p)}>
          <p className="menu-item">{lang ?? "SRB"}</p>
          <Image src={chevron} alt="" />
          <div>
            {openMenu && (
              <p onClick={handleLanguage} className="menu-item language-select">
                {lang ? (lang == "SRB" ? "ENG" : "SRB") : "ENG"}
              </p>
            )}
          </div>
        </div>
      );
    }
    

    typeof window !== "undefined" is a hack that would, most likely, lead to a hydration error.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search