Why are document, window, localStorage and sessionStorage undefined in client components?
I'm having this function in a client component
But I'm getting an error saying
ReferenceError: localStorage is not defined
.Why is that? Isn't it supposed to work in client components?
The name "client component" is actually quite misleading. It's not a component that exclusively runs in the browser. It's a component that runs on the server and the client. The code inside the component is executed first on the server and the client or in other words, it's prerendered on the server and then hydrated on the client.
During that initial prerendering, since the component is rendered on the server, it doesn't have access to the browser APIs named above. Hence you got that error.
There are 2 fixes for this problem:
- move logic using browser-specific APIs to
useEffect
(or an event handler, or any place that only runs on the client) - use the component dynamically with
next/dynamic
andssr: false
Moving logic to useEffect
If we move the logic inside useEffect
hook, it will only run on the client. So, we can use these APIs without any problem.
Note that if you do it this way, as you can see you need a loading state, which may cause a flash of unstyled content (FOUC). To overcome it, you have to use a <script>
(or next/script
) to get the value before hydration and configure styling based on that using vanilla JavaScript. For theming specifically, we recommend next-themes
which handles this problem very well, so you don't have to touch all this <script>
and useEffect
shenanigans.
By the way, there are already plenty of existing solutions made for many of these problems. For example, for localStorage
handling, you can have useLocalStorage
.
Using next/dynamic
with ssr: false
If we import a component dynamically with ssr: false
, it will only run on the client, at the cost of the content not being available in the initial HTML (so crawlers may not be able to see it). If that is fine for you, you can proceed to use these APIs without any problem.