Hydration error with SSG as soon as even a static variable is used
Unanswered
American black bear posted this in #help-forum
American black bearOP
I'm having a very weird issue since I moved to doing Static Site Generation. Now, there are places where as soon as I use a variable in my template, such as a static
In fact, even if I do something as simple as taking my copyright year and changing
I should also mention that something, my prettier adds some
I would appreciate any insights as to why this may be happening.
{staticVar}
will cause a hydration error. I've tried everything I could think of, like setting it to 0
and only changing its value from useEffect
, changing from a client component to a server component, passing the value from the server component as a prop to the client component, etc. Nothing works.In fact, even if I do something as simple as taking my copyright year and changing
2024
to {2024}
, the hydration error occurs. So essentially, as soon as a variable exists, the hydration error rears its ugly head and I am uncertain what else to try at the moment.I should also mention that something, my prettier adds some
{' '}
to retain some spaces. All of these have caused the same hydration error thus far as well.I would appreciate any insights as to why this may be happening.
60 Replies
Original message was deleted
American black bearOP
What do you mean? I haven't received anything apart from your message just now.
American black bearOP
Here's a more concrete example.
This does not cause a hydration error:
This causes a hydration error:
The idea being that the year should be dynamic but even just making it a static variable breaks hydration.
This does not cause a hydration error:
<span className="text-sm sm:text-center">
© 2024 Company. All Rights Reserved.
</span>
This causes a hydration error:
<span className="text-sm sm:text-center">
© {2024} Company. All Rights Reserved.
</span>
The idea being that the year should be dynamic but even just making it a static variable breaks hydration.
what happens if u compute the current year directly in the tsx?
without passing a variable
American black bearOP
I can't use a variable at all. The hydration error happens as soon as it's a variable. The year is the same in the source as what it should be. I'm resorting to trying string interpolation now to see if I can force the server and client to see the same thing.
I'm wondering if at the moment, using a straight variable will do the interpolation at the server level and the client has the JSX, seeing a difference. One hint that this could be an issue is that html entities were also giving me this problem, such as the copyright symbol being originally written as
I'm wondering if at the moment, using a straight variable will do the interpolation at the server level and the client has the JSX, seeing a difference. One hint that this could be an issue is that html entities were also giving me this problem, such as the copyright symbol being originally written as
©
.u need to share more information actually
does it happen on dev? what actual error do u get
take a screenshot of the error
usually nextjs shows exactly where the hydration error happens
American black bearOP
on dev, everything is dynamic so this problem does not occur. I am trying to get everything to work as SSG to gain the power of the CDN and edge for performance. So at the moment, I have to deploy to my sandbox every time to test because this doesn't occur in dev where things are always dynamic.
It doesn't show when I deploy statically because it's set as a production build
American black bearOP
it only says there's a hydration error and points online to the message but doesn't show the trace because it's a production build (only place where it happens when things are statically served)
and if u click on the link, it tell u that it is a hydration error right?
American black bearOP
yes
where do u think the error could happen in your code?
u shared some snippets
American black bearOP
it happens in many places but the easiest example to follow is the copyright one
so basically, on the page where the copyright component is, if u remove the dynamic part, no error?
American black bearOP
if statically written as
2024
, no problem. If made into a static variable {2024}
, hydration error.is that component client only?
American black bearOP
yes, that's a client component since it's the footer and requires knowing the user's logged in status to determine some links
American black bearOP
with the copyright, yes. But this happens in a bunch of other places, including some legal pages where my prettier simply added some
{' '}
to retain some spaces while wrappingI don't think the code will really help because there's really no reason why
2024
and {2024}
would be any different, yet the latter gives a hydration errori cant really help u if i dont know how your code looks like
its like im trying to guess for u what the error is without having something to work with š
American black bearOP
The snippet I sent for the copyright is the only part that matters though. My entire component works fine if I do
2024
but as soon as it's a variable {2024}
, the hydration error occurs so regardless of anything else in the component, that is 110% the culprit.well i know that, u dont have to tell me
then share a minimum reproduction repo if u dont want to share the code
American black bearOP
trying to find a smaller example. The footer is 300 lines
if u think, u correctly defined the variable without doing some weird manipulation between rendering and defining u can just make a small reproduction of that component and share it with stackblitz or whatever
cause the error can also happen if the value is set before the client component renders and changes while hydration
American black bearOP
I'm gonna temporarily slim down the footer and show you a reproducible example that's easier to use
yeah, but in this case, the value is static and cannot change, yet still yields the error
it's 2024 regardless if written statically or in a variable
is your 2024 var a string?
that u define
American black bearOP
I only tried as a number
that could the issue be
before u render that, convert it to a string
u can call toString() directly in tsx
American black bearOP
I slimmed down the footer as an example and I'm just confirming that the issue is still reproducible. I'll try with number and string as well while I test this.
American black bearOP
I just remember though that I did try converting to a string on another component and it didn't help. I'll try again here though just for completeness
Alright so here's the slimmed down footer where I just confirmed that the problem is still ocurring:
I left some state stuff in there to keep it almost the same as the full component but none of those should actually impact anything since they all work fine if I change
'use client'
import * as React from 'react'
import { useTheme } from 'next-themes'
export default function Footer(): React.ReactElement {
const [_apiUrl, setApiUrl] = React.useState<string>(`/v1/docs`)
const { systemTheme, theme } = useTheme()
const currentTheme = theme === 'system' ? systemTheme : theme
React.useEffect(() => {
setApiUrl(`/v1/docs?theme=${currentTheme === 'dark' ? 'dark' : 'light'}`)
}, [currentTheme])
return (
<footer className="sticky top-[100vh] bg-neutral-100 dark:bg-neutral-900">
<span className="text-secondary-text dark:text-secondary-text-dark text-sm sm:text-center">
© {2024} Company. All Rights Reserved.
</span>
</footer>
)
}
I left some state stuff in there to keep it almost the same as the full component but none of those should actually impact anything since they all work fine if I change
{2024}
to 2024
.Will try now with
{Number(2024).toString()}
@American black bear Will try now with `{Number(2024).toString()}`
that will probably work
American black bearOP
It's being deployed now for testing but I tried a string on another component and the hydration error still occurred.
Confirmed. Even as a string, the hydration error still occurs.
What I suspect the most at the moment is that because of SSG, the variables get interpolated and sent to the client that way. So I think the client is actually receiving/seeing
If that's the case, it's just unclear to me how the client is ever supposed to be able to take over without a hydration error when the initial file has been statically generated as SSG and will never have variables in it since they'll all already have been interpolated.
Ā© 2024 Company. All Rights Reserved.
from the server and then compares to © {2024} Company. All Rights Reserved.
and sees a difference.If that's the case, it's just unclear to me how the client is ever supposed to be able to take over without a hydration error when the initial file has been statically generated as SSG and will never have variables in it since they'll all already have been interpolated.
American black bearOP
This works:
I suspect I may have been on the right track with what I said above. I think the
{`Ā© ${new Date().getFullYear()} `}
I suspect I may have been on the right track with what I said above. I think the
{2024}
is simply causing an interpolation to happen and because of the, it's not the actual 2024
value that differs, it's the html entity ©
vs actual symbol Ā©