Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js手把手系列:03、路由篇 | 链接与导航 #90

Open
MagicalBridge opened this issue Jul 14, 2024 · 0 comments
Open

Next.js手把手系列:03、路由篇 | 链接与导航 #90

MagicalBridge opened this issue Jul 14, 2024 · 0 comments

Comments

@MagicalBridge
Copy link
Owner

前言

上篇我们介绍了如何定义路由,本篇我们讲讲如何在 Next.js 中实现链接和导航。

所谓“导航”,指的是使用 JavaScript 进行页面切换,通常会比浏览器默认的重新加载更快,因为在导航的时候,只会更新必要的组件,而不会重新加载整个页面。

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

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

<Link>组件

Next.js 的<Link>组件是一个拓展了原生 HTML <a> 标签的内置组件,用来实现预获取(prefetching) 和客户端路由导航。这是 Next.js 中路由导航的主要和推荐方式。

基础使用

基本的使用方式如下:

import Link from 'next/link'
 
export default function Page() {
  return <Link href="/dashboard">Dashboard</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() ,它会读取当前 URL 的路径名(pathname)。示例代码如下:

'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.push和 router.replace的时候,设置 scroll: false

// next/link
<Link href="/dashboard" scroll={false}>
  Dashboard
</Link>
// useRouter
import { useRouter } from 'next/navigation'
 
const router = useRouter()
 
router.push('/dashboard', { scroll: false })

注:关于 <Link> 组件的具体用法,我们还会在后面的文章中详细介绍。

useRouter() hook

第二种方式是使用 useRouter,这是 Next.js 提供的用于更改路由的 hook。使用示例代码如下:

'use client'
 
import { useRouter } from 'next/navigation'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

注意使用该 hook 需要在客户端组件中。(顶层的 'use client' 就是声明这是客户端组件)

注:关于 useRouter() hook 的具体用法,我们会在后面的文章中详细介绍。

redirect 函数

客户端组件使用 useRouter hook,服务端组件则可以直接使用 redirect 函数,这也是 Next.js 提供的 API,使用示例代码如下:

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')
  }
 
  // ...
}

注:关于 redirect() 函数的具体用法,我们会在后面的文章中详细介绍。

History API

也可以使用浏览器原生的 window.history.pushState 和 window.history.replaceState 方法更新浏览器的历史记录堆栈。通常与 usePathname(获取路径名的 hook) 和 useSearchParams(获取页面参数的 hook) 一起使用。

比如用 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) {
    // e.g. '/en/about' or '/fr/contact'
    const newPath = `/${locale}${pathname}`
    window.history.replaceState(null, '', newPath)
  }
 
  return (
    <>
      <button onClick={() => switchLocale('en')}>English</button>
      <button onClick={() => switchLocale('fr')}>French</button>
    </>
  )
}

总结

恭喜你,完成了本节内容的学习!

本篇我们介绍了 4 种实现导航的方式,但所涉及的具体概念如服务端组件、客户端组件、各种 hooks、函数方法等都未展开讲解,我们会在后续的文章中讲述。本篇可以作为概览,主要是为了方便大家写 Demo 的时候用到导航相关的内容。

参考链接

  1. https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant