Next.js Discord

Discord Forum

localStorage undefined

Unanswered
Xiasi Dog posted this in #help-forum
Open in Discord
Xiasi DogOP
I am trying to make a listbox with headlessui and I have implemented localStorage but I'm having a weird issue. Basically, I have the data storing and when I reload the page there isn't a flicker of the default option before my selected option is set. So it's PERFECT! However, I'm getting an issue in my terminal that says: localStorage is not defined. I've tried everything under the sun to fix it. Any help would be greatly appreciated. I sent my full code for my selectmenu.tsx and also a picture of the terminal. Thanks!

61 Replies

Nile Crocodile
localStorage can only be used in client components. Since it's part of window object, which exists only... well... on the client
@Nile Crocodile `localStorage` can only be used in client components. Since it's part of `window` object, which exists only... well... on the client
Xiasi DogOP
Yeah I have the 'use client' also but it still has the same error
  const [selected, setSelected] = useState(() => {
    // Initialize from local storage or default to people[3]
    const storedValue = localStorage.getItem("selectedPerson");
    return storedValue ? JSON.parse(storedValue) : people[0];
  });
thats the issue
put it in a useEffect
a client component runs on the server first
then on the client
so on the server render, it ignores any code in a useEffect
and hence whilst it server renders your client component, it find localStorage and calls it undefined
Nile Crocodile
Or you can make sure you're on client before trying to access localStorage:
if (typeof window !== 'undefined') { // if we're on client
  // do stuff with localStorage
}
@Arinji put it in a useEffect
Xiasi DogOP
Thanks for the help but now I have the issue that the selected variable is out of scope within the inner useEffect hook
Im still new to this stuff so my mind is exploding from this localstorage stuff haha
ignore the return stuff
i just wanna see the stuff before it
ping me btw, i have 25 other posts open xD
@Arinji show your updated code pls
Xiasi DogOP
useEffect(() => {
    const [selected, setSelected] = useState<{
      id: number;
      name: string;
      avatar: string;
    }>(() => {
      // Initialize from local storage or default to people[3]
      const storedValue = localStorage.getItem("selectedPerson");
      return storedValue ? JSON.parse(storedValue) : people[0];
    });

    useEffect(() => {
      // Update local storage when selected value changes
      localStorage.setItem("selectedPerson", JSON.stringify(selected));
    }, [selected]);
  }, []);
No worries haha! Thanks so much for the help!
uh ok so
Xiasi DogOP
So now it says selected is undefined lol its the undefined-ception
useEffect(() => {
    const [selected, setSelected] = useState<{
      id: number;
      name: string;
      avatar: string;
    }>({})        

    useEffect(() => {
      // Update local storage when selected value changes
      const item = localStorage.setItem("selectedPerson", JSON.stringify(selected));

setSelected( item ? JSON.parse(item) : people[0];);
    }, [selected]);
  }, []);
try that
@Xiasi Dog
if there are any syntax errors, feel free to fix them xD
discord coding is hard :(
@Arinji try that
Xiasi DogOP
I fixed the syntax but nope, my selected variable is still undefined
:pepecry:
can you log item btw
wait
wtf
im sorry im dumb
its getItem
what are we doing here lmao
change that to .getItem
@Arinji change that to .getItem
Xiasi DogOP
Do you mean the old code I had an just change it to getItem?
@Xiasi Dog Do you mean the old code I had an just change it to getItem?
no no, your old code was pretty wrong :D

basically what we are tying to do here is when your page loads, the state is first an empty object
then a useEffect runs which checks your localstorage
and sets your state accordingly
inside the useEffect
makes sense?
@Arinji no no, your old code was pretty wrong :D basically what we are tying to do here is when your page loads, the state is first an empty object
Xiasi DogOP
Gotcha! Here's my new code

 useEffect(() => {
    const [selected, setSelected] = useState<{
      id: number;
      name: string;
      avatar: string;
    }>({
      id: 0,
      name: "",
      avatar: "",
    });

    useEffect(() => {
      // Update local storage when selected value changes
      const item = localStorage.getItem("selectedPerson");
      setSelected(item ? JSON.parse(item) : people[0]);
    }, [selected, people]);
  }, []);


and still has my selected undefined
Dang what is that code xD
Xiasi DogOP
Typescript
why you wrapping everything in a big ol useEffect
@Xiasi Dog Typescript
its fine, i was joking lol
Xiasi DogOP
:pepecry:
Haha
const [selected, setSelected] = useState<{
      id: number;
      name: string;
      avatar: string;
    }>({
      id: 0,
      name: "",
      avatar: "",
    });

    useEffect(() => {
      // Update local storage when selected value changes
      const item = localStorage.getItem("selectedPerson");
console.log(item);
      setSelected(item ? JSON.parse(item) : people[0]);
    }, []);
there you go, try that
@Arinji there you go, try that
Xiasi DogOP
That worked!! So, now I just have one other question. Is it possible to make it so it doesnt have a split second of setting blank and instead it just loads the data right away? It just looks very weird when I refresh the page and it offets my navbar for a second
so for example, in your ui, you check if the id === 0, and if it is, you show something of the same height and width of when you actually have the userdata
this way when react hydrates and gets your localstorage data, your content wont move around
@Arinji its not possible for it to be instant, what you can do is make it have a default value
Xiasi DogOP
You know whats funny, is that when the localstorage was undefined at the beginning it actually was instant and it displayed my stored data correctly but it was that damn terminal console message I couldnt get passed. Haha. Coding is weird man.
@Arinji yup :(
Xiasi DogOP
Thanks for all the help. Much appreciated my friend. I guess I'll just do a skeleton load that sets the same height etc for my selectmenu
no worries :D
its a pretty documented thing and itsnt nextjs specific so feel free to see any youtube vids on it :D
mark a solution btw