Capítulo 384 de 456

useRouter

Core Idea

Hook do Pages Router pra acessar o objeto router (navegação client-side, query, path) dentro de qualquer function component.

Key Concepts

  • useRouter: hook de next/router; não funciona em class components (usar withRouter)
  • router.pathname: path do arquivo de rota após /pages, sem basePath/locale/trailing slash
  • router.query: objeto com query string + params de rota dinâmica; {} durante prerender sem SSR
  • router.asPath: path exibido no browser incluindo search params, sem basePath/locale
  • router.isReady: true quando os campos do router estão atualizados client-side; usar só dentro de useEffect
  • router.push(url, as, options): navegação client-side; options.shallow evita rerodar getStaticProps/getServerSideProps
  • router.replace: como push, mas não adiciona entrada no history
  • router.prefetch(url, as, options): prefetch manual, só produção
  • router.beforePopState(cb): intercepta evento popstate; retornar false assume controle manual
  • router.back() / router.reload(): window.history.back() / window.location.reload()
  • router.events: emissor de eventos (routeChangeStart, routeChangeComplete, routeChangeError, beforeHistoryChange, hashChangeStart, hashChangeComplete)
  • next/compat/router: mesmo hook, mas retorna NextRouter | null e funciona em app e pages durante migração
  • withRouter: HOC alternativo que injeta router como prop

Code Examples

import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()
  return (
    <button type="button" onClick={() => router.push('/about')}>
      Click me
    </button>
  )
}
  • O que demonstra: navegação client-side básica com router.push.
import { useRouter } from 'next/router'

export default function MyApp({ Component, pageProps }) {
  const router = useRouter()
  return <Component key={router.asPath} {...pageProps} />
}
  • O que demonstra: forçar remount de página com key={router.asPath} quando o state não deve persistir entre navegações da mesma rota dinâmica.
import { useEffect } from 'react'
import { useRouter } from 'next/compat/router'
import { useSearchParams } from 'next/navigation'
const MyComponent = () => {
  const router = useRouter() // may be null or a NextRouter instance
  const searchParams = useSearchParams()
  useEffect(() => {
    if (router && !router.isReady) return
    const search = searchParams.get('search')
  }, [router, searchParams])
}
  • O que demonstra: componente compartilhável entre app e pages usando next/compat/router.

Anti-patterns

  • Usar asPath antes de isReady: pode causar mismatch entre client e server em páginas SSR/estático-otimizadas
  • Ignorar ESLint no-floating-promises em router.push/replace/prefetch: essas chamadas retornam Promise; usar void ou await (exceto dentro de onClick)
  • Destructurar next/compat/router: useRouter() pode retornar null, então não dá pra desestruturar direto como no next/router puro

Key Takeaways

  1. router.push/replace aceitam UrlObject para navegação tipada, incluindo rotas dinâmicas via pathname + query
  2. Omitir pathname no push aplica a query à URL do browser (asPath), preservando rewrites
  3. next/compat/router é a ponte oficial pra migrar componentes de pages para app gradualmente
  4. Eventos do router (router.events) devem ser registrados em useEffect e desregistrados no cleanup

Connects To

  • useSearchParams (ch385): par usado junto de useRouter para ler/atualizar query string
  • next/link: cobre a maioria dos casos de navegação sem precisar de useRouter