Clock component causes hydration error due to changing text
Answered
Pixiebob posted this in #help-forum
PixiebobOP
Hi, I worked with react in the past and I'm using Next.js for the first time, which means it's my first time having to deal with client/server components and hydration.
I have the following component:
This component should just print the current time, and update it every second.
When I run my dev server, occasionally I get some errors in my devtools console:
- app-index.js:35 Warning: Text content did not match. Server: "7:08:18 PM" Client: "7:08:19 PM"
- app-index.js:35 Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.
- (5x) on-recoverable-error.js:20 Uncaught Error: Text content does not match server-rendered HTML.
- react-dom.development.js:14381 Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
After this, everything works as it should but I get the error indicator on my web page.
Is this not the correct way to do this? How should I implement a client-side clock component like this?
I have the following component:
import { useEffect, useState } from "react";
export default function () {
"use client";
const [time, setTime] = useState(new Date().toLocaleTimeString());
useEffect(() => {
console.log("Setting interval");
const interval = setInterval(() => {
console.log("Updating time");
setTime(new Date().toLocaleTimeString());
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<div className="flex items-center justify-center h-screen">
<h1 className="text-4xl">{time}</h1>
</div>
);
}This component should just print the current time, and update it every second.
When I run my dev server, occasionally I get some errors in my devtools console:
- app-index.js:35 Warning: Text content did not match. Server: "7:08:18 PM" Client: "7:08:19 PM"
- app-index.js:35 Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.
- (5x) on-recoverable-error.js:20 Uncaught Error: Text content does not match server-rendered HTML.
- react-dom.development.js:14381 Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
After this, everything works as it should but I get the error indicator on my web page.
Is this not the correct way to do this? How should I implement a client-side clock component like this?
Answered by Clown
So you can pretty much only avoid this problem by either actively telling the component "supressHydrationWarnings" which would disable these warning for only that level
20 Replies
PixiebobOP
One way I've found to work around this is by setting the initial value of my
I'm also aware that locale will differ between server and client. That's fine, it's not related to this question.
time state to an empty string, but that causes some flashing and defeats the point of hydration I'd think.I'm also aware that locale will differ between server and client. That's fine, it's not related to this question.
Asian black bear
Sounds pretty good. you found out the issue by yourself.
Congratulations.
Congratulations.
PixiebobOP
That's... not exactly what I was hoping to hear 😅
Is there no way to indicate that the hydrated html may be different due to dynamically changing values?
Is there no way to indicate that the hydrated html may be different due to dynamically changing values?
@Pixiebob That's... not exactly what I was hoping to hear 😅
Is there no way to indicate that the hydrated html may be different due to dynamically changing values?
Well not exactly. React expects the server rendering dom and the client's first render dom to be same
So you can pretty much only avoid this problem by either actively telling the component "supressHydrationWarnings" which would disable these warning for only that level
Answer
Or you use the isMounted approach
Asian black bear
Have you ever thought about leveraging the data-hydration-status attribute?
PixiebobOP
I'm not sure what the isMounted approach would be, but supressing hydration warnings sounds like what I want to do here. Thanks! I'll look into that
@Asian black bear Have you ever thought about leveraging the data-hydration-status attribute?
PixiebobOP
no, since I'm new to nextjs and I don't know about that :)
@Pixiebob I'm not sure what the isMounted approach would be, but supressing hydration warnings sounds like what I want to do here. Thanks! I'll look into that
IsMounted approach is using useEffect basically
Asian black bear
Next.js provides a data-hydration-status attribute on the root element of your page. This attribute can have one of two values: "hydrated" or "not-hydrated". You can use this information to conditionally render your components or update the UI based on the hydration status.
@Asian black bear Next.js provides a data-hydration-status attribute on the root element of your page. This attribute can have one of two values: "hydrated" or "not-hydrated". You can use this information to conditionally render your components or update the UI based on the hydration status.
Where are you pulling that out from?
PixiebobOP
I can't seem to find
data-hydration-status on googleYes cause that seems like something pulled out of GPT
Btw for reference you can take a lot at either react docs or this:
https://nextjs.org/docs/messages/react-hydration-error
https://nextjs.org/docs/messages/react-hydration-error
Both are for handling hydration issues
PixiebobOP
ah I hadn't found that page, seems very useful
I think I can solve it from here, thanks a lot!
Asian black bear
// pages/index.js
import { useState, useEffect } from 'react';
export default function Home() {
const [timestamp, setTimestamp] = useState(null);
useEffect(() => {
// Update the timestamp on the client-side
setTimestamp(new Date().toLocaleString());
}, []);
return (
<div data-hydration-status={timestamp ? 'hydrated' : 'not-hydrated'}>
<h1>Current Timestamp</h1>
{timestamp ? (
<p>{timestamp}</p>
) : (
<p>Loading...</p>
)}
</div>
);
}
this is an example code using data-hydration-status.
import { useState, useEffect } from 'react';
export default function Home() {
const [timestamp, setTimestamp] = useState(null);
useEffect(() => {
// Update the timestamp on the client-side
setTimestamp(new Date().toLocaleString());
}, []);
return (
<div data-hydration-status={timestamp ? 'hydrated' : 'not-hydrated'}>
<h1>Current Timestamp</h1>
{timestamp ? (
<p>{timestamp}</p>
) : (
<p>Loading...</p>
)}
</div>
);
}
this is an example code using data-hydration-status.
@Asian black bear // pages/index.js
import { useState, useEffect } from 'react';
export default function Home() {
const [timestamp, setTimestamp] = useState(null);
useEffect(() => {
// Update the timestamp on the client-side
setTimestamp(new Date().toLocaleString());
}, []);
return (
<div data-hydration-status={timestamp ? 'hydrated' : 'not-hydrated'}>
<h1>Current Timestamp</h1>
{timestamp ? (
<p>{timestamp}</p>
) : (
<p>Loading...</p>
)}
</div>
);
}
this is an example code using data-hydration-status.
Can you tell me where you got this
data-hydration-status from? Also if you are using useEffect anyways then you literally have no need for that attribute.