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

在Nextjs里,有四种方式可以实现路由导航

  • 使用<Link>组件
  • 使用useRouterHook(客户端组件)
  • 使用redirect函数(服务端组件)
  • 使用浏览器原生History API

Link组件


基础使用

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

在上一篇中,404导航到首页就是用的这个:

import Link from "next/link";

const NotFound: React.FC = () => {
  return (
    <div>
      <h2>Not Found</h2>
      <p>Could not find requested resource</p>
      <Link href="/">Return Home</Link>
    </div>
  );
};

export default NotFound;

支持动态渲染

支持路由链接动态渲染

import Link from "next/link";

interface BlogProps {
  id: number;
  title: string;
  slug: string;
}

const mockBlog: BlogProps[] = [
  {
    id: 1,
    title: "First blog",
    slug: "first-blog",
  },
  {
    id: 2,
    title: "Second blog",
    slug: "second-blog",
  },
];

const BlogPage: React.FC = () => {
  return (
    <ul>
      {mockBlog.map((blog) => (
        <li key={blog.id}>
          <Link href={`/blog/${blog.slug}`}>{blog.title}</Link>
        </li>
      ))}
    </ul>
  );
};

export default BlogPage;

获取当前路径名

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

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import clsx from "clsx";

interface BlogProps {
  id: number;
  title: string;
  slug: string;
}

const mockBlog: BlogProps[] = [
  {
    id: 1,
    title: "First blog",
    slug: "/dashboard/first-blog",
  },
  {
    id: 2,
    title: "Second blog",
    slug: "/dashboard/second-blog",
  },
  {
    id: 3,
    title: "disable blog",
    slug: "/dashboard/linkExample",
  },
];

const BlogPage: React.FC = () => {
  const pathname = usePathname();
  return (
    <ul>
      {mockBlog.map((blog) => {
        const isActive = pathname === blog.slug;

        console.log("isActive", isActive);

        return (
          <li
            key={blog.id}
            className={clsx(isActive ? "text-blue-500" : "text-white")}
          >
            <Link href={`${blog.slug}`}>{blog.title}</Link>
          </li>
        );
      })}
    </ul>
  );
};

export default BlogPage;

跳转行为设置

APP Router的默认行为就是滚从到新的路由的顶部,或者在前进后退的时候维持之前的滚动的距离。

如果你想要禁用这个行为,你可以给<Link>组件传递一个scroll={false}属性,或者在使用router.pushrouter.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 })

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' 就是声明这是客户端组件)

具体用法在后面的记录文章会详细介绍

redirect 函数

这也是Nextjs自带的一个API,服务端组件用的,和客户端的useRouter区别开来。

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

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

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

这段代码的作用就是点击按钮切换路由里面的参数?sort=

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>
    </>
  )
}
最后修改:2024 年 05 月 13 日
收款不要了,给孩子补充点点赞数吧