App and path are (determined by the url from ctx) and are passed down as props from getServerSideProps to the component.
// Hook
export default function usePath(app, path) {
const [currentPath, setCurrentPath] = useState('')
useEffect(() => {
const config = globalConfig[app]
if (config) {
const { paths } = globalConfig
const isMatching = paths.find(({ pattern }) => pattern.test(path))
if (isMatching) {
setCurrentPath(isMatching.path)
}
}
}, [app, path])
return currentPath
}
Component utilizing the hook:
const currentPath = usePath(app, path)
// Hydration error here:
<p>{app && currentPath ? t(`sentence.${currentPath}`) : t(`sentence.defaultMessage`)}</p>
/*
Server renders: sentence.defaultMessage,
while the client renders: sentence.${currentPath}.
*/
Why do I get a hydration miss match in this case?
If I omit useState and the useEffect, and just handle this without these hooks it works (storing in a let var instead). But I'm interested in the underlying issue.
Works:
export default function useChainPath(app, path) {
const config = globalConfig[app]
let currentPath = ''
if (config) {
const { paths } = config
const isMatching = paths.find(({ pattern }) => pattern.test(path))
if (isMatching) {
currentPath = isMatching.path
}
}
return currentPath
}