二、Routing

郁子大约 4 分钟约 1204 字笔记NextJSCodevolution

(一)Routing in a React app

  • 安装第三方路由库
  • 创建 routes.js 路由配置文件
  • 对于每条路由,创建一个组件文件,导出该组件,在 routes.js 中导入它,并使用 path 属性指定路由

(二)Routing in a Next.js app

  • 基于文件系统的路由机制
  • 当将文件添加到项目中的 pages 文件夹时,它将自动成为可用的路由
  • 通过将文件名与嵌套文件夹结构混合和匹配,几乎可以定义最常见的路由模式
    • Route with Pages:页面路由
    • Nested routes:嵌套路由
    • Dynamic routes:动态路由
    • Catch-all routes:全方位路由
    • Navigate from the UI:从 UI 组件中导航
    • Programmatically navigate b/w Pages:编程导航 b/w 页面

(三)Routing with Pages —— 页面路由

  • 路由路径等同于 pages 文件夹下定义的文件名
  • 基于页面的路由机制,页面根据其文件名与路由相关联

1. pages/_app.js

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}
export default MyApp;

2. pages/index.js

  • 访问 localhost:3000/
function Home() {
  return <h1>Home Page</h1>;
}
export default Home;

3. pages/about.js

  • 访问 localhost:3000/about
function About() {
  return <h1>About Page</h1>;
}
export default About;

4. pages/profile.js

  • 访问 localhost:3000/profile
function Profile() {
  return <h1>Profile Page</h1>;
}
export default Profile;

(四)Nested Routes —— 嵌套路由

  • pages 下文件夹将映射为路由多级路径
  • 嵌套路由——嵌套文件夹结构,文件将自动以相同的方式在 URL 中映射路由

1. pages/blog.js

  • 访问 localhost:3000/blog
function Blog() {
  return <h1>Blog Page</h1>;
}
export default Blog;
  • 将该文件移动到 pages/blog 目录下,并重命名为 index.js,访问 localhost:3000/blog 依旧能访问该页面
  • 推荐

2. pages/blog/first.js

  • 访问 localhost:3000/blog/first
function FirstBlog() {
  return <h1>First Blog Page</h1>;
}
export default FirstBlog;

3. pages/blog/second.js

  • 访问 localhost:3000/blog/second
function SecondBlog() {
  return <h1>Second Blog Page</h1>;
}
export default SecondBlog;

(五)Dynamic Routes —— 动态路由

  • 使用 [] 定义文件名,将在渲染时根据 [] 内的参数动态形成路由路径
  • 使用 useRouter 钩子函数获取文件名参数
  • 路由路径匹配到页面路由和动态路由时,优先渲染页面路由

1. pages/product/index.js

  • 访问 localhost:3000/product
function ProductList() {
  return (
    <>
      <h2>Product 1</h2>
      <h2>Product 2</h2>
      <h2>Product 3</h2>
    </>
  );
}
export default ProductList;

2. pages/product/[productId].js

  • 访问 localhost:3000/product/1
  • 访问 localhost:3000/product/2
  • 访问 localhost:3000/product/3
  • 访问 localhost:3000/product/100
import { useRouter } from "next/router";

function ProductDetail() {
  const router = useRouter();
  const productId = router.query.productId;
  return <h1>Details about product {productId}</h1>;
}
export default ProductDetail;

(六)Nested Dynamic Routes —— 嵌套动态路由

  • 使用 [] 定义文件夹名,将在渲染时根据 [] 内的参数动态形成多级路由路径

1. pages/product/[productId]/index.js

  • 访问 localhost:3000/product/1
  • 访问 localhost:3000/product/2
  • 访问 localhost:3000/product/3
  • 访问 localhost:3000/product/100
import { useRouter } from "next/router";

function ProductDetail() {
  const router = useRouter();
  const productId = router.query.productId;
  return <h1>Details about product {productId}</h1>;
}
export default ProductDetail;

2. pages/product/[productId]/review/[reviewId].js

  • 访问 localhost:3000/product/1/review/1
  • 访问 localhost:3000/product/2/review/2
  • 访问 localhost:3000/product/3/review/3
  • 访问 localhost:3000/product/100/review/5
import { useRouter } from "next/router";

function Review() {
  const router = useRouter();
  const { productId, reviewId } = router.query;
  return (
    <h1>
      Review {reviewId} for product {productId}
    </h1>
  );
}
export default Review;

(七)Catch All Routes —— 全方位路由

  • 使用 [...参数] 定义文件名,将匹配地址栏输入的任意参数
  • 当希望为相同的页面提供不同的 url 时,或者处理一些路由参数可选的页面时使用

1. pages/docs/[...params].js

  • 访问 localhost:3000/docs 将跳转 404 页面
  • 访问 localhost:3000/docs/feature1
  • 访问 localhost:3000/docs/feature1/concept1
  • 访问 localhost:3000/docs/feature1/concept1/example1
import { useRouter } from "next/router";

function Doc() {
  const router = useRouter();
  const { params = [] } = router.query;

  if (params.length === 2) {
    return (
      <h1>
        Viewing docs for feature {params[0]} and concept {params[1]}
      </h1>
    );
  } else if (params.length === 1) {
    return <h1>Viewing docs for feature {params[0]}</h1>;
  }

  return <h1>Docs Home Page</h1>;
}
export default Doc;

2. pages/docs/[[...params]].js

  • 访问 localhost:3000/docs 将正常返回 Doc 页面
  • 组件 prop 可以收到动态路由参数
  • Link 组件默认使用 push 跳转,使用 replace 属性切换
  • Link 组件跳转是客户端跳转,不会和 a 标签一样重新请求服务器页面导致刷新

1. pages/index.js

import Link from "next/link";

function Home() {
  return (
    <div>
      <h1>Home Page</h1>
      <Link href="/blog">
        <a>Blog</a>
      </Link>
      <br />
      <Link href="/product">
        <a>Products</a>
      </Link>
    </div>
  );
}
export default Home;

2. pages/product/index.js

import Link from "next/link";

function ProductList({ productId = 100 }) {
  return (
    <>
      <Link href="/">
        <a>Home</a>
      </Link>

      <h2>
        <Link href="/product/1">
          <a>Products 1</a>
        </Link>
      </h2>
      <h2>
        <Link href="/product/2">
          <a>Products 2</a>
        </Link>
      </h2>
      <h2>
        <Link href="/product/3" replace>
          <a>Products 3</a>
        </Link>
      </h2>

      <h2>
        <Link href={`/product/${productId}`}>
          <a>Products {productId}</a>
        </Link>
      </h2>
    </>
  );
}
export default ProductList;

(九)Navigating Programmatically —— 编程式路由导航

  • useRouter 钩子函数提供 pushreplace 方法,以实现编程时路由跳转

1. pages/index.js

import Link from "next/link";
import { useRouter } from "next/router";

function Home() {
  const router = useRouter();

  const handleClick = () => {
    console.log("Placing your order.");
    // router.push("/product");
    router.replace("/product");
  };

  return (
    <div>
      <h1>Home Page</h1>

      <Link href="/blog">
        <a>Blog</a>
      </Link>
      <br />
      <Link href="/product">
        <a>Products</a>
      </Link>

      <button onClick={handleClick}>Place Order</button>
    </div>
  );
}
export default Home;

(十)Custom 404 Page —— 自定义 404 页面

  • NextJS 默认提供了 404 页面(没有显示在目录中)
  • pages 目录下创建 404.js 文件会替换默认提供的 404 页面

1. pages/404.js

function PageNotFound() {
  return <h1>404 Page with all the custom styling necessary.</h1>;
}
export default PageNotFound;
上次编辑于: