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

Error when using server-side rendering (SSR) #24

Closed
haydn opened this issue Jul 25, 2019 · 10 comments
Closed

Error when using server-side rendering (SSR) #24

haydn opened this issue Jul 25, 2019 · 10 comments

Comments

@haydn
Copy link

haydn commented Jul 25, 2019

Overview

This hook currently throws this error when used with ReactDOMServer:

ReferenceError: window is not defined
    at eval (webpack:///./node_modules/react-use-localstorage/dist/react-use-localstorage.esm.js?:12:5)

This happens because it's trying to access localStorage when getting the initial value (runpkg link):

const [value, setValue] = React.useState(
() => localStorage.getItem(key) || initialValue
);

Note: The function that is passed to useEffect isn't executed on a server, so accessing localStorage there doesn't cause any problems.

Expected Behaviour

The initialValue is always used when rendering on the server.

Current Behaviour

It throws an error.

Workaround

An easy way to workaround this issue is to wrap it in a custom hook:

const useSSRLocalStorage = (key, initial) =>
  typeof window !== "undefined" ? useLocalStorage(key, initial) : [initial];
@dance2die
Copy link
Owner

Hi @haydn Thanks for the SSR issue and the workaround for it.

I think the implementation of useSSRLocalStorage might be better to be mentioned in the README instead of adding it to the library as it's so simple and probably not used all the time.

@stale
Copy link

stale bot commented Nov 25, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix This will not be worked on label Nov 25, 2019
@stale stale bot closed this as completed Dec 2, 2019
@henrycatalinismith
Copy link

henrycatalinismith commented Feb 3, 2020

Just leaving a quick drive-by comment to thank @haydn for the workaround for this issue. I'm using this hook in a Gatsby project where all components need to be SSR safe and it fixed my problem!

Here's what I came up with to satisfy TypeScript's complaints about the workaround:

const useSsrLocalStorage = (key: string, initial: string): [string, React.Dispatch<string>] => {
  return typeof window === 'undefined'
    ? [initial, (value: string) => undefined]
    : useLocalStorage(key, initial)
}

@dance2die dance2die reopened this Feb 4, 2020
@stale stale bot removed the wontfix This will not be worked on label Feb 4, 2020
@dance2die
Copy link
Owner

#34 to associate the issue.

@otherjohn
Copy link

PLEASE PLEASE PLEASE reference this fix for Gastby users. I spent days trying to track down what was happening. @haydn and @hencatsmith (I use Typescript) fix was great for my Gastby build error!

@dance2die
Copy link
Owner

dance2die commented Jun 23, 2020

Hi @otherjohn.

I've updated README with @hencatsmith's workaround

@dance2die dance2die reopened this Jun 23, 2020
@Aditya94A
Copy link

Where exactly should you put this useSsr hook?

I get the following error:

 React Hook "useLocalStorage" is called conditionally. React Hooks must be called in the exact same order in every
 component render  react-hooks/rules-of-hooks

@haydn
Copy link
Author

haydn commented Sep 4, 2020

@AdityaAnand1 Ah, yes. That linter is probably upset that we're calling useLocalStorage inside a conditional, which is technically against the rules. In practice this isn't actually going to be a problem because the condition isn't going to change between updates (it's always going to one condition on the server and the other condition on the client).

A workaround for now would be to disable the ESLint rule:

const useSSRLocalStorage = (key, initial) =>
  typeof window !== "undefined" ? useLocalStorage(key, initial) : [initial]; // eslint-disable-line react-hooks/rules-of-hooks

@dance2die This might be a reason to solve the problem inside the hook instead of leaving it to users to workaround it. SSR is becoming a lot more common with things like Gatsby and Next.js rising in popularity, so I think you're going to keep seeing people run into this.

@westprophet
Copy link

westprophet commented Dec 26, 2020

const useSSRLocalStorage = (key, initial) => typeof window !== "undefined" ? useLocalStorage(key, initial) : [initial]; // eslint-disable-line react-hooks/rules-of-hooks
image

This code doesn't work for Next.js ^ 10. Any way, I could not apply it although I really wanted to.

@westprophet
Copy link

If anyone can help suggest how to apply this hook in next.js so that it works, I would be very grateful

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

No branches or pull requests

6 participants