Nextjs 入门踩坑系列(二)——路由篇| 导航🚀

2,126 阅读2分钟

【欢迎订阅我的Nextjs 15专栏,有你需要的入门必备常识】

上篇我们了解如何初始化一个Nextjs项目,如何定义路由【可移步初始Nextjs路由

本篇讲讲如何在Nextjs实现导航

"导航",就是使用JavaScript进行页面切换,通常比浏览器默认重新加载更快。因为只会加载必要组件,不会全部加载整个页面,类似“懒加载”的功能。

在Next.js中,有4种方式实现路由导航:

  1. 使用 <Link> 组件
  2. 使用 useRouter Hook(客户端组件)
  3. 使用 redirect 函数(服务端组件)
  4. 使用浏览器原生 History API

<Link> 组件:推荐的导航方式

Next.js 的 <Link> 组件是基于原生 HTML <a> 标签扩展而来的,它不仅能实现页面跳转,还能进行预获取(prefetching),这可是 Next.js 推荐的路由导航方式。

基础用法

先来看最简单的用法。比如你想从当前页面跳转到“Dashboard”页面,代码可以这样写:

import Link from 'next/link'

export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

动态路由的渲染

有时候,页面的链接是动态生成的,比如一个博客列表,每篇文章都有自己的链接。这时候,<Link> 组件也能轻松搞定:

import Link from 'next/link'

export default function PostList({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

获取当前路径名

如果你需要根据当前路径名来判断链接是否处于激活状态,可以用 usePathname()。比如在导航栏中,给当前激活的链接加上特殊样式:

'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Navigation({ navLinks }) {
  const pathname = usePathname()

  return (
    <>
      {navLinks.map((link) => {
        const isActive = pathname === link.href

        return (
          <Link
            className={isActive ? 'text-blue' : 'text-black'}
            href={link.href}
            key={link.name}
          >
            {link.name}
          </Link>
        )
      })}
    </>
  )
}

跳转行为的设置

默认情况下,App Router 会在跳转到新路由时滚动到页面顶部,或者在前进后退时保持之前的滚动位置。如果你不想这样,可以在 <Link> 组件中加上 scroll={false} 属性,或者在使用 router.pushrouter.replace 时设置 scroll: false

// 使用 <Link> 组件
<Link href="/dashboard" scroll={false}>
  Dashboard
</Link>

// 使用 useRouter
import { useRouter } from 'next/navigation'

const router = useRouter()

router.push('/dashboard', { scroll: false })

useRouter() Hook:客户端路由的利器

useRouter 是 Next.js 提供的一个 Hook,专门用来在客户端组件中更改路由。用起来也很简单,比如你想通过按钮点击跳转到“Dashboard”页面:

'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

需要注意的是,useRouter 只能在客户端组件中使用哦,记得在文件顶部加上 'use client' 声明。

redirect 函数:服务端组件的跳转

如果你在服务端组件中需要进行路由跳转,可以直接使用 redirect 函数。比如在获取数据失败时,跳转到登录页面:

import { redirect } from 'next/navigation'

async function fetchTeam(id) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect('/login')
  }

  // ...
}

History API:原生的路由控制

除了 Next.js 自带的路由方法,你还可以使用浏览器原生的 window.history.pushStatewindow.history.replaceState 方法来更新浏览器的历史记录。

比如,你想对一个产品列表进行排序,可以用 pushState

'use client'

import { useSearchParams } from 'next/navigation'

export default function SortProducts() {
  const searchParams = useSearchParams()

  function updateSorting(sortOrder) {
    const params = new URLSearchParams(searchParams.toString())
    params.set('sort', sortOrder)
    window.history.pushState(null, '', `?${params.toString()}`)
  }

  return (
    <>
      <button onClick={() => updateSorting('asc')}>Sort Ascending</button>
      <button onClick={() => updateSorting('desc')}>Sort Descending</button>
    </>
  )
}

如果想切换应用的语言设置,可以用 replaceState,这样用户就无法通过后退按钮回到之前的语言设置:

'use client'

import { usePathname } from 'next/navigation'

export default function LocaleSwitcher() {
  const pathname = usePathname()

  function switchLocale(locale) {
    const newPath = `/${locale}${pathname}`
    window.history.replaceState(null, '', newPath)
  }

  return (
    <>
      <button onClick={() => switchLocale('en')}>English</button>
      <button onClick={() => switchLocale('fr')}>French</button>
    </>
  )
}

总结

通过这几种方式,Next.js 提供了灵活的路由导航解决方案,无论是客户端还是服务端,都能轻松实现页面跳转。虽然我们今天只是简单介绍了这些方法,但它们已经足够你在写 Demo 的时候使用了。后续我们会详细讲解更多相关概念,比如客户端组件和服务端组件的区别,以及各种 Hooks 和函数的深入用法。

参考链接

Next官方路由与导航

Next手把手指南