useRouter

Uygulamanızdaki herhangi bir işlev bileşeninin içindeki router nesnesine erişmek istiyorsanız, useRouter kancasını kullanabilirsiniz, aşağıdaki örneğe bir göz atın:

import { useRouter } from 'next/router'
 
function ActiveLink({ children, href }) {
  const router = useRouter()
  const style = {
    marginRight: 10,
    color: router.asPath === href ? 'red' : 'black',
  }
 
  const handleClick = (e) => {
    e.preventDefault()
    router.push(href)
  }
 
  return (
    <a href={href} onClick={handleClick} style={style}>
      {children}
    </a>
  )
}
 
export default ActiveLink

useRouter bir React Hook'udur , yani sınıflarla kullanılamaz. Ya withRouter kullanabilir ya da sınıfınızı bir fonksiyon bileşenine sarabilirsiniz.

router object

Aşağıda, her ikisi tarafından döndürülen router nesnesinin tanımı yer almaktadır useRouter ve withRouter:

Sayfa sunucu tarafı oluşturma veya otomatik statik optimizasyon kullanılarak oluşturulmuşsa, asPath alanının kullanılması istemci ve sunucu arasında bir uyumsuzluğa yol açabilir. isReady alanı true olana kadar asPath alanını kullanmaktan kaçının.

Aşağıdaki yöntemler router içinde yer almaktadır:

router.push

İstemci tarafı geçişlerini işler, bu yöntem aşağıdaki durumlar için kullanışlıdır next/link yeterli değil.

router.push(url, as, options)

Harici URL'ler için router.push kullanmanıza gerek yoktur. window.location bu durumlar için daha uygundur.

Önceden tanımlanmış bir rota olan pages/about.js adresine gidiliyor:

import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/about')}>
      Click me
    </button>
  )
}

Dinamik bir rota olan pages/post/[pid].js adresinde gezinme:

import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/post/abc')}>
      Click me
    </button>
  )
}

Kullanıcıyı pages/login.js adresine yönlendirmek, kimlik doğrulamanın arkasındaki sayfalar için kullanışlıdır:

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
// Here you would fetch and return the user
const useUser = () => ({ user: null, loading: false })
 
export default function Page() {
  const { user, loading } = useUser()
  const router = useRouter()
 
  useEffect(() => {
    if (!(user || loading)) {
      router.push('/login')
    }
  }, [user, loading])
 
  return <p>Redirecting...</p>
}

Resetting state after navigation

Next.js'de aynı sayfaya gidildiğinde, ana bileşen değişmediği sürece React bağlantıyı kaldırmadığı için sayfanın durumu varsayılan olarak sıfırlanmayacaktır.

pages/[slug].js
import Link from 'next/link'
import { useState } from 'react'
import { useRouter } from 'next/router'
 
export default function Page(props) {
  const router = useRouter()
  const [count, setCount] = useState(0)
  return (
    <div>
      <h1>Page: {router.query.slug}</h1>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase count</button>
      <Link href="/one">one</Link> <Link href="/two">two</Link>
    </div>
  )
}

Yukarıdaki örnekte, /one ve /two arasında gezinmek sayımı sıfırlamaz. En üst düzey React bileşeni olan Page aynı olduğu için useState render'lar arasında korunur.

Bu davranışı istemiyorsanız, birkaç seçeneğiniz vardır:

With URL object

Bir URL nesnesini aşağıdakiler için kullanabileceğiniz şekilde kullanabilirsiniz next/link. Hem url hem de as parametreleri için çalışır:

import { useRouter } from 'next/router'
 
export default function ReadMore({ post }) {
  const router = useRouter()
 
  return (
    <button
      type="button"
      onClick={() => {
        router.push({
          pathname: '/post/[pid]',
          query: { pid: post.id },
        })
      }}
    >
      Click here to read more
    </button>
  )
}

router.replace

replace 'daki pervaneye benzer şekilde next/link, router.replace history yığınına yeni bir URL girişi eklenmesini engelleyecektir.

router.replace(url, as, options)

Aşağıdaki örneğe bir göz atın:

import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.replace('/home')}>
      Click me
    </button>
  )
}

router.prefetch

Daha hızlı istemci tarafı geçişleri için sayfaları önceden getirin. Bu yöntem, yalnızca istemci tarafında next/linkçünkü next/link sayfaları otomatik olarak önceden getirme işlemini gerçekleştirir.

Bu yalnızca üretime yönelik bir özelliktir. Next.js geliştirme aşamasında sayfaları önceden getirmez.

router.prefetch(url, as, options)

Diyelim ki bir giriş sayfanız var ve giriş yaptıktan sonra kullanıcıyı kontrol paneline yönlendiriyorsunuz. Bu durumda, aşağıdaki örnekte olduğu gibi daha hızlı bir geçiş yapmak için gösterge tablosunu önceden getirebiliriz:

import { useCallback, useEffect } from 'react'
import { useRouter } from 'next/router'
 
export default function Login() {
  const router = useRouter()
  const handleSubmit = useCallback((e) => {
    e.preventDefault()
 
    fetch('/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        /* Form data */
      }),
    }).then((res) => {
      // Do a fast client-side transition to the already prefetched dashboard page
      if (res.ok) router.push('/dashboard')
    })
  }, [])
 
  useEffect(() => {
    // Prefetch the dashboard page
    router.prefetch('/dashboard')
  }, [router])
 
  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      <button type="submit">Login</button>
    </form>
  )
}

router.beforePopState

Bazı durumlarda (örneğin, Özel Sunucu kullanıyorsanız), popstate adresini dinlemek ve yönlendirici buna göre hareket etmeden önce bir şeyler yapmak isteyebilirsiniz.

router.beforePopState(cb)

cb, false döndürürse Next.js yönlendiricisi popstate ile ilgilenmez ve bu durumda bu işlemden siz sorumlu olursunuz. Dosya sistemi yönlendirmesini devre dışı bırakma bölümüne bakın.

İsteği değiştirmek için beforePopState adresini kullanabilir veya aşağıdaki örnekte olduğu gibi bir SSR yenilemesini zorlayabilirsiniz:

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  useEffect(() => {
    router.beforePopState(({ url, as, options }) => {
      // I only want to allow these two routes!
      if (as !== '/' && as !== '/other') {
        // Have SSR render bad routes as a 404.
        window.location.href = as
        return false
      }
 
      return true
    })
  }, [router])
 
  return <p>Welcome to the page</p>
}

router.back

Geçmişte geri gitme. Tarayıcının geri düğmesine tıklamaya eşdeğerdir. window.history.back() adresini çalıştırır.

import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.back()}>
      Click here to go back
    </button>
  )
}

router.reload

Geçerli URL'yi yeniden yükleyin. Tarayıcının yenile düğmesine tıklamaya eşdeğerdir. window.location.reload() adresini çalıştırır.

import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.reload()}>
      Click here to reload
    </button>
  )
}

router.events

Next.js Router içinde gerçekleşen farklı olayları dinleyebilirsiniz. İşte desteklenen olayların bir listesi:

Bildiğim iyi oldu: Burada url tarayıcıda gösterilen URL'dir. basePath.

Örneğin, yönlendirici olayını dinlemek için routeChangeStart, pages/_app.js adresini açın veya oluşturun ve aşağıdaki gibi olaya abone olun:

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
export default function MyApp({ Component, pageProps }) {
  const router = useRouter()
 
  useEffect(() => {
    const handleRouteChange = (url, { shallow }) => {
      console.log(
        `App is changing to ${url} ${
          shallow ? 'with' : 'without'
        } shallow routing`
      )
    }
 
    router.events.on('routeChangeStart', handleRouteChange)
 
    // If the component is unmounted, unsubscribe
    // from the event with the `off` method:
    return () => {
      router.events.off('routeChangeStart', handleRouteChange)
    }
  }, [router])
 
  return <Component {...pageProps} />
}

Bu örnekte olaya abone olmak için bir Özel Uygulama (pages/_app.js) kullanıyoruz çünkü sayfa gezintilerinde kaldırılmıyor, ancak uygulamanızdaki herhangi bir bileşendeki yönlendirici olaylarına abone olabilirsiniz.

Yönlendirici olayları, bir bileşen bağlandığında(useEffect veya componentDidMount / componentWillUnmount) veya zorunlu olarak bir olay gerçekleştiğinde kaydedilmelidir.

Bir rota yüklemesi iptal edilirse (örneğin, art arda iki bağlantıya hızlı bir şekilde tıklanarak), routeChangeError ateşlenecektir. Ve iletilen err, aşağıdaki örnekte olduğu gibi true olarak ayarlanmış bir cancelled özelliği içerecektir:

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
export default function MyApp({ Component, pageProps }) {
  const router = useRouter()
 
  useEffect(() => {
    const handleRouteChangeError = (err, url) => {
      if (err.cancelled) {
        console.log(`Route to ${url} was cancelled!`)
      }
    }
 
    router.events.on('routeChangeError', handleRouteChangeError)
 
    // If the component is unmounted, unsubscribe
    // from the event with the `off` method:
    return () => {
      router.events.off('routeChangeError', handleRouteChangeError)
    }
  }, [router])
 
  return <Component {...pageProps} />
}

Potential ESLint errors

router nesnesinde erişilebilen belirli yöntemler bir Promise döndürür. ESLint kuralı no-floating-promises etkinleştirilmişse, bunu genel olarak veya etkilenen satır için devre dışı bırakmayı düşünün.

Uygulamanızın bu kurala ihtiyacı varsa, ya void promise'i kullanmalı ya da bir async fonksiyonu kullanmalı, await Promise'i kullanmalı ve ardından fonksiyon çağrısını geçersiz kılmalısınız. Bu, yöntem bir onClick işleyicisinin içinden çağrıldığında geçerli değildir.

Etkilenen yöntemler şunlardır:

Potential solutions

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
// Here you would fetch and return the user
const useUser = () => ({ user: null, loading: false })
 
export default function Page() {
  const { user, loading } = useUser()
  const router = useRouter()
 
  useEffect(() => {
    // disable the linting on the next line - This is the cleanest solution
    // eslint-disable-next-line no-floating-promises
    router.push('/login')
 
    // void the Promise returned by router.push
    if (!(user || loading)) {
      void router.push('/login')
    }
    // or use an async function, await the Promise, then void the function call
    async function handleRouteChange() {
      if (!(user || loading)) {
        await router.push('/login')
      }
    }
    void handleRouteChange()
  }, [user, loading])
 
  return <p>Redirecting...</p>
}

withRouter

Eğer useRouter sizin için en uygunu değilse, withRouter aynı router nesnesini herhangi bir bileşene de ekleyebilir.

Usage

import { withRouter } from 'next/router'
 
function Page({ router }) {
  return <p>{router.pathname}</p>
}
 
export default withRouter(Page)

TypeScript

Sınıf bileşenlerini withRouter ile kullanmak için bileşenin bir yönlendirici prop kabul etmesi gerekir:

import React from 'react'
import { withRouter, NextRouter } from 'next/router'
 
interface WithRouterProps {
  router: NextRouter
}
 
interface MyComponentProps extends WithRouterProps {}
 
class MyComponent extends React.Component<MyComponentProps> {
  render() {
    return <p>{this.props.router.pathname}</p>
  }
}
 
export default withRouter(MyComponent)