Skip to content

路由

旧款路由 Page Router ,新款路由 App Router 。

Page Router ,about.ts contact.ts 映射为 /about 和 /contact ,意味着组件 table.ts list.ts 得另外存放。两个文件夹,页面和组件,维护麻烦。

App Router ,考虑页面和组件共存,加深文件层级,约定页面为 page.ts ,布局为 layout.ts ,加载为 loading.ts 。about/page.ts contact/page.ts 映射为 /about 和 /contact 。

加深层级,依赖约定,利弊各半。

加载边界,简单方案使用约定 loading.ts 。

// app/book/loading.ts

export default function Loading() {
  return <div>Loading...</div>;
}

缩小加载边界,可以使用 React 组件 <Suspense>

新建文件 app/book/data.json ,模拟数据。

[
    {
        "id": 1,
        "name": "西游记"
    },
    {
        "id": 2,
        "name": "水浒传"
    },
    {
        "id": 3,
        "name": "三国演义"
    },
    {
        "id": 4,
        "name": "红楼梦"
    }
]

动态路由,服务端异步

// app/book/[slug]/page.tsx
// 详情页,对应 URL 为 /book/[slug]

export default async function Page({
  params
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params;

  return <div>图书 {slug}</div>;
}

查询字符串,search page pageSize 等,服务端异步

// app/book/page.tsx
// 列表页,对应 URL 为 /book

export default async function Page({
  searchParams
}: {
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
  const { search = '', page = '1', pageSize = '10' } = await searchParams;

  return <div>
    搜索 {search},第 {page} 页,每页 {pageSize} 条
  </div>;
}

查询字符串,客户端

// app/book/search.tsx
// 组件

'use client'

import { useSearchParams } from 'next/navigation';

export default function SearchBar() {
  const searchParams = useSearchParams();
  const search = searchParams.get('search') ?? '';

  return <div>搜索 {search}</div>;
}

联系 math@baima.site