Skip to content

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

Description

@MagicalBridge

前言

上篇我们介绍了如何定义路由,本篇我们讲讲如何在 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 中路由导航的主要和推荐方式。

基础使用

基本的使用方式如下:

importLinkfrom'next/link'exportdefaultfunctionPage(){return<Linkhref="/dashboard">Dashboard</Link>}

支持动态渲染

支持路由链接动态渲染:

importLinkfrom'next/link'exportdefaultfunctionPostList({ posts }){return(<ul>{posts.map((post)=>(<likey={post.id}><Linkhref={`/blog/${post.slug}`}>{post.title}</Link></li>))}</ul>)}

获取当前路径名

如果需要对当前链接进行判断,你可以使用 usePathname() ,它会读取当前 URL 的路径名(pathname)。示例代码如下:

'use client'import{usePathname}from'next/navigation'importLinkfrom'next/link'exportfunctionNavigation({ navLinks }){constpathname=usePathname()return(<>{navLinks.map((link)=>{constisActive=pathname===link.hrefreturn(<LinkclassName={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<Linkhref="/dashboard"scroll={false}>
Dashboard
</Link>
// useRouterimport{useRouter}from'next/navigation'constrouter=useRouter()router.push('/dashboard',{scroll: false})

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

useRouter() hook

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

'use client'import{useRouter}from'next/navigation'exportdefaultfunctionPage(){constrouter=useRouter()return(<buttontype="button"onClick={()=>router.push('/dashboard')}>
Dashboard
</button>)}

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

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

redirect 函数

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

import{redirect}from'next/navigation'asyncfunctionfetchTeam(id){constres=awaitfetch('https://...')if(!res.ok)returnundefinedreturnres.json()}exportdefaultasyncfunctionProfile({ params }){constteam=awaitfetchTeam(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'exportdefaultfunctionSortProducts(){constsearchParams=useSearchParams()functionupdateSorting(sortOrder){constparams=newURLSearchParams(searchParams.toString())params.set('sort',sortOrder)window.history.pushState(null,'',`?${params.toString()}`)}return(<><buttononClick={()=>updateSorting('asc')}>Sort Ascending</button><buttononClick={()=>updateSorting('desc')}>Sort Descending</button></>)}

replaceState 会替换浏览器历史堆栈的当前条目,替换后用户无法后退,比如切换应用的地域设置(国际化):

'use client'import{usePathname}from'next/navigation'exportdefaultfunctionLocaleSwitcher(){constpathname=usePathname()functionswitchLocale(locale){// e.g. '/en/about' or '/fr/contact'constnewPath=`/${locale}${pathname}`window.history.replaceState(null,'',newPath)}return(<><buttononClick={()=>switchLocale('en')}>English</button><buttononClick={()=>switchLocale('fr')}>French</button></>)}

总结

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

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

参考链接

  1. https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions