DEV Community

Persisting React State in localStorage

🌈 Josh on February 24, 2020

This is a cross-post from my personal blog. View it there for at least 35% more whimsy! Let's say we're building a calendar app, like Google Cal...
Collapse
 
fmgordillo profile image
Facundo Martin Gordillo • Edited

Awesome post!!

Additional things to consider, if someone wants to implement this:

1) If you are concern about variable type, you should make additional changes into useStickyState() by two ways: Detecting the variable inside the function or passing an additional arg (i.e: 'integer')
2) "The label you give it has to be unique", one option for that could be creating a Set outside the function, and control if that label is being created or not, and throw a warning in the code.

But that's too fancy and all, I really prefer your solution :)

And welcome to Dev.to ;)

Collapse
 
1000machines profile image
Andrzej Koper

Great post!
Seems like exactly what I need.
But unfortunately I can't get it to work with nextjs.
I probably miss something obvious. ;)
Have a look at this code sandbox ( codesandbox.io/s/nextjs-localstora... )
console shows correctly the value from localstorage but select tag is always set to first option.

Collapse
 
joshwcomeau profile image
🌈 Josh • Edited

Right! So I realized, my solution wasn't actually great for SSR 😬

It turns out this is a really hard problem for SSR. Here's a version that "works":

function useStickyState(defaultValue, key) {
  const [value, setValue] = React.useState(defaultValue);

  React.useEffect(() => {
    const stickyValue =
      window.localStorage.getItem(key);

    if (stickyValue !== null) {
      setValue(JSON.parse(stickyValue));
    }
  }, [key])

  React.useEffect(() => {
    window.localStorage.setItem(
      key,
      JSON.stringify(value)
    );
  }, [key, value]);

  return [value, setValue];
}

"Works" is in quotes because there's still a problem with this one, which is that the initial state still flashes. In your CodeSandbox, it briefly shows "Day" before being reset to the sticky value.

The ideal solution would be to hide this component until it's rendering on the client. It's impossible for the "initial" painted value to have the correct value, since the server has no idea what value is stored in your computer's localStorage.

Incidentally my next blog post will be on this subject, so I'll have more info then :D

Sorry for the confusion!

Collapse
 
1000machines profile image
Andrzej Koper

Oh. I see. this makes sense.
Looking forward to you blog post :)
cheers.