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

fix: Hydration Error #1

Merged
merged 1 commit into from
Feb 23, 2023
Merged

fix: Hydration Error #1

merged 1 commit into from
Feb 23, 2023

Conversation

ethanmick
Copy link
Owner

This was an annoying little bug. On certain versions of Node.js the
function Date.prototype.toLocaleString() does not use a regular
unicode space for the seperator, but rather a U+202F Narrow No-Break
Space.

> Buffer.from('8:30 AM')
<Buffer 38 3a 33 30 e2 80 af 41 4d>

// E280AF is Narrow No-Break Space!
// https://codepoints.net/U+202F

> Buffer.from('8:30 AM')
<Buffer 38 3a 33 30 20 41 4d>

This is only true for the Node.js side though, not the browser rendered
version. So when then client renders the string it uses a normal space,
resulting in a hydration error mismatch.

nodejs/node#46123

There are two ways to fix this.

  1. Clean the string on the server side by removing the unusual
    whitespace.
  2. Only render the time on the browser

While option 1 seems okay initially, it's open to new issues in the
future. The truth is that the code can't make assumptions about how the
string will appear and we are rendering it on two differnt platforms,
Node.js and the client browser. Different browsers may render the string
even more differently and there will still be a mismatch. V8 vs Gecko
for example.

Therefore, the best solution is to just render the final string on the
client. To do so, we move the only the time rendering component into
it's own file and dynamically import it. Also turn server side rendering
off.

This isn't ideal, but because of the complexity of strings and dates,
it's the only way to ensure there is no hydration mismatch.

Reported by Sivanth_P http://www.youtube.com/channel/UCXWFDIEFQwbIzxU-nkHV90w

Thanks!

This was an annoying little bug. On certain versions of Node.js the
function `Date.prototype.toLocaleString()` does not use a regular
unicode space for the seperator, but rather a U+202F Narrow No-Break
Space.

```
> Buffer.from('8:30 AM')
<Buffer 38 3a 33 30 e2 80 af 41 4d>

// E280AF is Narrow No-Break Space!
// https://codepoints.net/U+202F

> Buffer.from('8:30 AM')
<Buffer 38 3a 33 30 20 41 4d>
```

This is only true for the Node.js side though, not the browser rendered
version. So when then client renders the string it uses a normal space,
resulting in a hydration error mismatch.

nodejs/node#46123

There are two ways to fix this.

1. Clean the string on the server side by removing the unusual
   whitespace.
2. Only render the time on the browser

While option 1 seems okay initially, it's open to new issues in the
future. The truth is that the code can't make assumptions about how the
string will appear and we are rendering it on two differnt platforms,
Node.js and the client browser. Different browsers may render the string
even more differently and there will still be a mismatch. V8 vs Gecko
for example.

Therefore, the best solution is to just render the final string on the
client. To do so, we move the only the time rendering component into
it's own file and dynamically import it. Also turn server side rendering
off.

This isn't ideal, but because of the complexity of strings and dates,
it's the only way to ensure there is no hydration mismatch.

Reported by Sivanth_P http://www.youtube.com/channel/UCXWFDIEFQwbIzxU-nkHV90w

Thanks!
@ethanmick ethanmick self-assigned this Feb 23, 2023
@ethanmick ethanmick merged commit 957d18b into main Feb 23, 2023
@ethanmick ethanmick deleted the ethanmick/fix-hydration-error branch February 23, 2023 14:17
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

Successfully merging this pull request may close these issues.

1 participant