nextjs app router hydration error

214 阅读1分钟

Guess: nextjs will render client component at server and then hydate it at client.

  • todo: check why this happen

how to resolve it

step 1

create Client only compoent

'use client'

import * as React from 'react'

export default function ClientOnly({ children }: { children: React.ReactNode }) {
  const [isMounted, setIsMounted] = React.useState(false)

  React.useEffect(() => {
    setIsMounted(true)
  }, [])

  if (!isMounted) return null

  return children
}

create useMediaQuery hook

import { useEffect, useState } from 'react'

export function useMediaQuery(query: string): boolean {
  const getMatches = (query: string): boolean => {
    // Prevents SSR issues
    if (typeof window !== 'undefined') {
      return window.matchMedia(query).matches
    }
    return false
  }

  const [matches, setMatches] = useState<boolean>(getMatches(query))

  function handleChange() {
    setMatches(getMatches(query))
  }

  useEffect(() => {
    const matchMedia = window.matchMedia(query)

    // Triggered at the first client-side load and if query changes
    handleChange()

    // Listen matchMedia
    if (matchMedia.addListener) {
      matchMedia.addListener(handleChange)
    } else {
      matchMedia.addEventListener('change', handleChange)
    }

    return () => {
      if (matchMedia.removeListener) {
        matchMedia.removeListener(handleChange)
      } else {
        matchMedia.removeEventListener('change', handleChange)
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [query])

  return matches
}

create Search component use client screen query just like normal components.

const isMd = useMediaQuery('(min-width: 750px)'
return isMd ?
 <div className="items-center justify-between flex">
  <Input
    placeholder="Please enter keyword to search"
    value={text}
    onChange={(e) => {
      const newText = e.target.value
      setText(newText)
      startSearching(() => {
        router.push(`${lng}/support/search/${newText}`)
      })
    }}
  />
  <Button type="primary" className="ml-4 min-w-[160px] " icon={<SearchOutlined />}>
    Search
  </Button>
</div>
:null

step2

<ClientOnly>
    <Search {...searchProps} />
</ClientOnly>    

better solution

use tailwind responsive-design in css, here is the link:tailwindcss.com/docs/respon…