Created
May 13, 2024 16:59
-
-
Save nitedani/357a9f298eb0b8e4393df706e8868a16 to your computer and use it in GitHub Desktop.
DateTime component that fixes React SSR and Client rendering mismatch.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useId, useMemo } from "react"; | |
export const DateTime = ( | |
props: { | |
date?: Date | null; | |
format: (date: Date) => string; | |
placeholder?: string; | |
} & React.HTMLAttributes<"span"> | |
) => { | |
const { format, date } = props; | |
const key = useId(); | |
if (!date) { | |
return props.placeholder; | |
} | |
const id = `__placeholder__${key}`; | |
const idScript = `__placeholder__${key}__script`; | |
const allFormattedDates: { [key: string]: string } = {}; | |
const localOffsetHours = -(new Date().getTimezoneOffset() / 60).toFixed(1); | |
let localFormattedDate: string; | |
if (import.meta.env.SSR) { | |
const allOfsetsHours = [ | |
+0.0, +1.0, +2.0, +3.0, +3.5, +4.0, +4.5, +5.0, +5.5, +5.75, +6.0, +6.5, | |
+7.0, +8.0, +8.75, +9.0, +9.5, +10.0, +10.5, +11.0, +12.0, +12.75, +13.0, | |
+13.75, +14.0, -1.0, -2.0, -2.5, -3.0, -3.5, -4.0, -4.5, -5.0, -6.0, -7.0, | |
-8.0, -9.0, -9.5, -10.0, -11.0, -12.0, | |
]; | |
for (const offsetHours of allOfsetsHours) { | |
allFormattedDates[offsetHours] = format( | |
new Date( | |
date.getTime() + (offsetHours - localOffsetHours) * 60 * 60 * 1000 | |
) | |
).replaceAll("\u202F", " "); | |
} | |
localFormattedDate = allFormattedDates[localOffsetHours]; | |
} else { | |
// eslint-disable-next-line react-hooks/rules-of-hooks | |
localFormattedDate = useMemo(() => format(date), [format, date]); | |
} | |
return ( | |
<> | |
<span id={id} className={props.className} style={props.style}> | |
{localFormattedDate} | |
</span> | |
<script | |
id={idScript} | |
dangerouslySetInnerHTML={{ | |
__html: import.meta.env.SSR | |
? ` | |
{ | |
const allFormattedDates = JSON.parse('${JSON.stringify( | |
allFormattedDates | |
)}'); | |
const localOffsetHours = -(new Date().getTimezoneOffset() / 60).toFixed(1); | |
const localFormattedDate = allFormattedDates[localOffsetHours]; | |
document.getElementById('${id}').innerHTML = localFormattedDate; | |
document.getElementById('${idScript}').innerHTML= ''; | |
} | |
` | |
: "", | |
}} | |
></script> | |
</> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment