astoilkov / use-local-storage-state

React hook that persists data in localStorage
MIT License
1.09k stars 39 forks source link

"ReferenceError: localStorage is not defined" when upgrading to v14.0.0 #37

Closed ha-ku closed 2 years ago

ha-ku commented 2 years ago

I'm writing a Next.js SSR project and I'm using this package for storing dark mode preference in local storage. After upgrading to v14.0.0, I changed my code into something like this:

export default function App({ Component, pageProps }) {
    const [userDarkMode, setUserDarkMode] = createLocalStorageHook('userDarkMode', {ssr: true, defaultValue: 'auto'})();
    ...
}

This results in the ReferenceError mentioned in the title.

More logs:

ReferenceError: localStorage is not defined
--
20:06:20.441 | at useLocalStorageState (/vercel/path0/node_modules/use-local-storage-state/src/useLocalStorageState.js:21:9)
20:06:20.441 | at useLocalStorage (/vercel/path0/node_modules/use-local-storage-state/src/createLocalStorageHook.js:13:126)
20:06:20.442 | at App (/vercel/path0/.next/server/pages/_app.js:72:7)

Seems like localStorage.getItem(key) === null leads to this problem.

Am I using the new version of this package in the right way?

astoilkov commented 2 years ago

Oops, sorry, fixing it right away. I will notify you soon.

astoilkov commented 2 years ago

Done. A new release is available. Sorry for the inconvenience.

astoilkov commented 2 years ago

By the way, I would recommend moving createLocalStorageHook outside of the component — you can look at the example usage in the readme.

ha-ku commented 2 years ago

By the way, I would recommend moving createLocalStorageHook outside of the component — you can look at the example usage in the readme.

I'm thinking about this too. How much does the position of createLocalStorageHook matter? Actually I'm also using this package in another hooks I wrote for my project, which makes it a little hard to move all of them outside the component. If this is strongly advised, I probably need to redesign those hooks for this.

astoilkov commented 2 years ago

You just need to know that you shouldn't change the argument passed to createLocalStorageHook. Changing the key, ssr or defaultValue will break the code. Some changes will break it in a subtler way than others.

However, from what I'm hearing you are probably changing the key maybe as this is one of the reasons it may be hard to refactor?

ha-ku commented 2 years ago

It just feels like writting something like const useSomeState = () => useState(someDefaultValue) outside a component, which seems a little confusing for me. For example, if I need to let the user choose their city in a list. The default city may depend on which contry the user chose before. The code might be something like this right now:

const CITIES = {
  country1: [city1, city2],
  country2: [city3]
}

export default MyComponent({contry}) {
  const [city, setCity] = useLocalStorageState('city', CITIES[country]);
  ...
}

How could the code be properly written under circumstances like this?

astoilkov commented 2 years ago

I think you are right. I've probably made a mistake. Keep an eye on this issue — https://github.com/astoilkov/use-local-storage-state/issues/38. I will post any updates there.