Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useLocalStorage mismatches server render #702

Open
saiichihashimoto opened this issue Oct 24, 2019 · 15 comments
Open

useLocalStorage mismatches server render #702

saiichihashimoto opened this issue Oct 24, 2019 · 15 comments
Labels
enhancement New feature or request

Comments

@saiichihashimoto
Copy link

Any server rendering solution won't have access to a browser's local storage, so it will default to the initialValue. Since useLocalStorage will use the actual local storage value on first render, this will immediately end up in a react hydration mismatch anytime the local storage value is not equal to the initialValue.

@streamich
Copy link
Owner

What would be possible solutions?

@saiichihashimoto
Copy link
Author

Have the state be some sane default (maybe specified by the user, maybe null) and then fill it with local storage in a useEffect, which only happens on the browser. It would be up to the user how to handle the default.

@streamich
Copy link
Owner

I believe currently it returns a default value (undefined by default) on the server: https://github.com/streamich/react-use/blob/master/src/useLocalStorage.ts#L9

And sets that value in useEffect hook on the browser: https://github.com/streamich/react-use/blob/master/src/useLocalStorage.ts#L32

Do you mean it should return undefined on the browser, too?

@saiichihashimoto
Copy link
Author

At least on the first render, yeah. If you console output the value, you can see what I mean. In the server, it'll be the initial value, but on the browser the first render will be whatever is in local storage, which means the hydration won't match.

@streamich
Copy link
Owner

Maybe we can add an option, if true, that would on the browser return the default value first, and only then re-render with a real value?

@saiichihashimoto
Copy link
Author

That would solve my issues!

@streamich streamich added the enhancement New feature or request label Nov 9, 2019
@dlbnco
Copy link

dlbnco commented Aug 4, 2020

You can also try disabling SSR for the component that is using local storage state.

In Next.js, for instance, you could do this:

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)

https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr

@saiichihashimoto
Copy link
Author

@dlbnco this avoids the problem by removing all the benefits of SSR for that component, which seems like a regression rather than a progression of features. The solution that doesn't disable SSR benefits to use the hook seems like the way to go.

@dlbnco
Copy link

dlbnco commented Aug 5, 2020

@saiichihashimoto that is true, although you could also use the loading option to load the same component (without state from localstorage) as a placeholder on SSR. Local storage is not available on the server anyway, so I think it would not cause any regression.

https://nextjs.org/docs/advanced-features/dynamic-import#with-custom-loading-component

@saiichihashimoto
Copy link
Author

@dlbnco that's one way to solve it. What I'm claiming is that the hook's issue can be isolated to the hook, rather than requiring the entire component be blocked out via SSR. This lets the implementer decide how they want to handle the situation where the value isn't loaded on the frontend rather than the blanket solution where they don't show the component, since the component itself has no issues showing.

@xobotyi
Copy link
Contributor

xobotyi commented May 15, 2021

SSR is well supported in upcoming hook of @react-hookz/web react-hookz/web#43

@JoeDuncko
Copy link

JoeDuncko commented Sep 2, 2021

Quick update: SSR is now fully supported by the useLocalStorageValue and useSessionStorageValue hooks included in @react-hookz/web! For reference, here are the docs on useLocalStorageValue and useSessionStorageValue.

If you are thinking of migrating, we have created a handy react-use to @react-hookz/web migration guide. Hope it helps!

@alnorris
Copy link

alnorris commented Nov 11, 2022

This works for me.

import { useRendersCount, useLocalStorage } from 'react-use'

const defaultValue = 'default'

const ShowValue = () => {
  const [value, setValue] = useLocalStorage('value', defaultValue)
  const isFirst = useRendersCount() === 1;

  return (
    <>
      <button type="button" onClick={() => setValue('new value')}>Set value </button>
      {isFirst ? defaultValue : value}
    </>
  )
}

@medmin
Copy link

medmin commented Dec 2, 2022

I use useLocalStorage in nextjs 13, and it still throws error

@lechinoix
Copy link

@streamich Would you like a PR on this one ? It is indeed quite annoying, I am using Next 13 too and it creates big errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

8 participants