1

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
}
octavemirbeau
  • 481
  • 6
  • 19

1 Answers1

3

useEffect doesn't run on the server, as it only runs after markup has rendered to the dom. So when usePath runs on the server the value of currentPath never gets set, and always stays undefined. Only when it gets to the client, after initial render useEffect runs.

To overcome this please consider using useMemo instead of useEffect+useState.

export default function usePath(app, path) {
  const currentPath = useMemo(()=>{
    const config = globalConfig[app]

    if (config) {
      const { paths } = globalConfig

      return paths.find(({ pattern }) => pattern.test(path))

    }
  }, [app, path])

  return currentPath
}
Ben Carp
  • 24,214
  • 9
  • 60
  • 72