基础使用

本指南将带你了解 @feoe/fs-router 的基础使用方法。

目录结构约定

@feoe/fs-router 使用文件系统作为路由的基础,遵循以下约定:

src/routes/ ├── layout.tsx # 根布局组件 ├── page.tsx # 首页 (/) ├── about/ │ └── page.tsx # /about 页面 ├── user/ │ ├── layout.tsx # 用户页面布局 │ ├── page.tsx # /user 页面 │ └── [id]/ │ └── page.tsx # /user/:id 页面 └── error.tsx # 错误页面

页面组件

基础页面

每个 page.tsx 文件代表一个路由页面:

1// src/routes/page.tsx
2export default function HomePage() {
3  return (
4    <div>
5      <h1>欢迎使用 fs-router</h1>
6      <p>这是首页</p>
7    </div>
8  )
9}

嵌套页面

通过文件夹嵌套创建嵌套路由:

1// src/routes/about/page.tsx
2export default function AboutPage() {
3  return (
4    <div>
5      <h1>关于我们</h1>
6      <p>这是关于页面</p>
7    </div>
8  )
9}

布局组件

根布局

layout.tsx 文件定义页面布局:

1// src/routes/layout.tsx
2import { Outlet } from 'react-router-dom'
3
4export default function RootLayout() {
5  return (
6    <div className="app">
7      <header>
8        <nav>
9          <a href="/">首页</a>
10          <a href="/about">关于</a>
11          <a href="/user">用户</a>
12        </nav>
13      </header>
14      <main>
15        <Outlet />
16      </main>
17      <footer>
18        <p>&copy; 2024 My App</p>
19      </footer>
20    </div>
21  )
22}

嵌套布局

可以为特定路由段创建专门的布局:

1// src/routes/user/layout.tsx
2import { Outlet } from 'react-router-dom'
3
4export default function UserLayout() {
5  return (
6    <div className="user-layout">
7      <aside>
8        <nav>
9          <a href="/user">用户首页</a>
10          <a href="/user/profile">个人资料</a>
11          <a href="/user/settings">设置</a>
12        </nav>
13      </aside>
14      <div className="user-content">
15        <Outlet />
16      </div>
17    </div>
18  )
19}

动态路由

使用方括号 [] 创建动态路由:

1// src/routes/user/[id]/page.tsx
2import { useParams } from 'react-router-dom'
3
4export default function UserDetailPage() {
5  const { id } = useParams()
6  
7  return (
8    <div>
9      <h1>用户详情</h1>
10      <p>用户 ID: {id}</p>
11    </div>
12  )
13}

错误处理

创建 error.tsx 文件处理错误:

1// src/routes/error.tsx
2import { useRouteError } from 'react-router-dom'
3
4export default function ErrorPage() {
5  const error = useRouteError()
6  
7  return (
8    <div className="error-page">
9      <h1>出错了!</h1>
10      <p>抱歉,发生了意外错误。</p>
11      <p>
12        <i>{error?.statusText || error?.message}</i>
13      </p>
14    </div>
15  )
16}

导航

1import { Link } from 'react-router-dom'
2
3export default function Navigation() {
4  return (
5    <nav>
6      <Link to="/">首页</Link>
7      <Link to="/about">关于</Link>
8      <Link to="/user/123">用户详情</Link>
9    </nav>
10  )
11}

编程式导航

1import { useNavigate } from 'react-router-dom'
2
3export default function MyComponent() {
4  const navigate = useNavigate()
5  
6  const handleClick = () => {
7    navigate('/about')
8  }
9  
10  return (
11    <button onClick={handleClick}>
12      前往关于页面
13    </button>
14  )
15}

数据加载

在 React-Router 的设计中 Loader 仅支持 DataRouter 数据路由

定义 loader

1// src/routes/user/[id]/page.data.ts
2import { fetchUser } from '@/services/user.service.ts'
3
4export async function loader({ params }) {
5  const user = await fetchUser(params.id)
6  return { user }
7}

使用 loader

1// src/routes/user/[id]/page.tsx
2import { useLoaderData } from 'react-router-dom'
3import { loader } from './page.data'
4
5export default function UserDetailPage() {
6  const { user } = useLoaderData<typeof loader>()
7  
8  return (
9    <div>
10      <h1>{user.name}</h1>
11      <p>{user.email}</p>
12    </div>
13  )
14}