Wasp 页面与路由(Pages & Routes)入门:用 route 与 page 声明构建 React 应用导航
【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp
在 Wasp 中,页面与路由的声明式配置是搭建 Web 应用导航骨架的核心。本文以 Wasp 0.17 版本文档 03-pages.md 为主线,带你完整掌握route与page两种声明的写法、URL 动态参数(:param)的用法、如何用 React Router 的useParams读取参数,以及如何通过类型安全的Link组件与routes对象构建可靠的页面跳转。读完本文,你将能够独立为 Wasp 项目新增任意数量的页面,并清理出适合继续开发的干净骨架。
认识main.wasp中的 page 与 route
main.wasp是 Wasp 应用的定义文件,整个文件就是一系列"声明"(declaration)的集合。其中与页面导航直接相关的有两种:
route:描述页面在哪个 URL 路径(path)下可被访问,并指定由哪个页面(page)来渲染;page:定义一个 Web 页面,以及页面被加载时应渲染的 React 组件。
使用wasp new TodoApp -t minimal创建的新项目,其默认的main.wasp文件中就自带一对route与page声明(JavaScript 与 TypeScript 版本的差异仅在于组件文件扩展名.jsx/.tsx):
route RootRoute { path: "/", to: MainPage } page MainPage { // 指定页面的 React 实现从 src/MainPage.{jsx,tsx} 中导出。 // 该语句使用标准 JS import 语法。 // 使用 @src 引用 src 文件夹内的文件。 component: import { MainPage } from "@src/MainPage" }这两条声明合在一起的含义是:当用户访问/时,Wasp 渲染src/MainPage.{jsx,tsx}中导出的命名导出(named export)组件。你不需要编写任何路由注册、<Routes>包裹或<BrowserRouter>初始化代码——Wasp 会根据这些声明自动生成客户端路由逻辑。
从仓库源码看,route声明的语义在 web/docs/advanced/routing.md 中有更完整的阐述:Wasp 底层使用React Router,路由路径支持 React Router 的全部标准匹配模式(参数段、可选段、splat 通配等)。而 Wasp 0.17 的教程采用经典的.waspDSL 写法,新版main.wasp.ts(TS 配置)则通过@wasp.sh/spec的route()与page()函数表达同样的语义,例如 examples/tutorials/TodoApp/main.wasp.ts 中的route("RootRoute", "/", page(MainPage, { authRequired: true }))。两种写法的核心概念完全一致:路径 + 页面组件。
MainPage 组件:一个普通的 React 函数组件
被page声明引用的 React 组件本身没有任何 Wasp 魔法,它就是一个普通的函数式组件:
import Logo from './assets/logo.svg'; import './Main.css'; export function MainPage() { // ... }组件同样可以像普通 React 项目一样导入 CSS 和静态资源(如assets目录下的 logo)。也就是说,你只需要写这些代码就够了,定义、构建、运行 Web 应用所需的其余一切,都由 Wasp 负责处理。
作为对照,教程最终完成的 TodoApp 里,examples/tutorials/TodoApp/src/MainPage.jsx 展示了页面组件如何进一步使用 Wasp 的能力:通过wasp/client/operations导入useQuery与getTasks等操作来读取数据。这印证了"页面组件就是标准 React 组件 + Wasp 生成的能力"这一设计理念。
新增页面:route + page 声明与动态 URL 参数
要添加更多页面,只需再创建一组route与page声明。你甚至可以为 URL 路径添加参数,语法与 React Router 完全一致——用:参数名声明动态段:
route HelloRoute { path: "/hello/:name", to: HelloPage } page HelloPage { component: import { HelloPage } from "@src/HelloPage" }当用户访问/hello/their-name时,Wasp 渲染src/HelloPage.{jsx,tsx}导出的组件。在组件内部,使用react-router-dom的useParamshook 读取name参数:
import { useParams } from 'react-router-dom' export const HelloPage = () => { const { name } = useParams<'name'>() return <div>Here's {name}!</div> }现在访问/hello/johnny,页面就会显示 "Here's johnny!"。
useParams<'name'>中的泛型参数是 TypeScript 的"参数名类型提示",让解构出来的name拥有正确的字符串类型。从源码结构看,web/docs/advanced/routing.md 还列举了更多 React Router 路径模式在 Wasp 中的用法:
- 可选段(Optional Segments):路径段后追加
?使该段可选,例如/photo/:photoId/edit?; - Splat 通配:路径末尾使用
/*匹配剩余任意段,例如/files/*,组件内通过useParams()解构"*"键获取匹配的剩余路径。
这些模式在 Wasp 0.17 的route声明中同样适用(参见 web/versioned_docs/version-0.17/advanced/links.md 中关于 splat 路由route CatchAllRoute { path: "/pages/*", to: CatchAllPage }的示例)。
TypeScript 进阶:类型安全的链接
如果你使用 TypeScript,Wasp 还提供了类型安全的导航能力,避免手写 URL 字符串出错:
Link组件(从wasp/client/router导入):通过to指定路由路径、params传入参数,编译期即可校验路径与参数是否匹配。例如对于path: "/task/:id"的路由:
import { Link } from 'wasp/client/router' // <Link to="/task/:id" params={{ id: task.id }}>{task.description}</Link>routes对象:同样从wasp/client/router导入,每个已声明的路由都会生成一个.build()函数:
import { routes } from 'wasp/client/router' const linkToTask = routes.TaskRoute.build({ params: { id: 1 } }) // → /task/1对于 splat 路由(如/pages/*),用params={{ '*': 'about' }}生成/pages/about;对于含可选静态段的路由(如/task/:id/details?),则需在build或Link的to中明确选择包含或不包含可选段的路径。Link还支持search(如{ sortBy: 'date' }→?sortBy=date)与hash(如#comments)属性,用于构造带查询串与锚点的链接。完整 API 与参数类型可查看 web/versioned_docs/version-0.17/advanced/links.md。
清理脚手架:为 TodoApp 准备干净的骨架
在开始实现 Todo 应用的核心功能之前,先把 starter 项目清理干净。
第一步,将MainPage组件的代码缩减为最小可渲染内容:
export const MainPage = () => { return <div>Hello world!</div> }此时主页面应当如下图所示:
第二步,删除不再需要的文件:src/Main.css、src/assets/logo.svg,以及src/HelloPage.{jsx,tsx}(教程后续不再需要这个页面)。
第三步,由于src/HelloPage.{jsx,tsx}已不存在,同步从main.wasp中移除它对应的route与page声明。清理后的main.wasp应如下:
app TodoApp { wasp: { version: "{latestWaspVersion}" }, title: "TodoApp", head: [ "<link rel='icon' href='/favicon.ico' />", ] } route RootRoute { path: "/", to: MainPage } page MainPage { component: import { MainPage } from "@src/MainPage" }这里有几个值得注意的细节:
app声明是 Wasp 项目的顶层配置,wasp.version用于固定要使用的 Wasp 版本,title用作浏览器标签页标题(Wasp 中所有字符串必须使用双引号),head数组可注入<head>中的 HTML 标签(如 favicon);- 清理的原则是"文件与声明一一对应":删除了组件文件,就必须删除对应的
route/page声明,否则 Wasp 会因引用了不存在的组件而报错。
完成以上清理后,你已具备对 Wasp 页面与路由的基础认知,可以开始实现 TodoApp 的核心功能了。
小结
本文围绕 Wasp 0.17 教程的 Pages & Routes 章节,梳理了从声明到实践的完整链路:
- 声明即导航:
route决定 URL 路径,page决定渲染组件,二者配对即可新增页面,无需手写路由代码; - 动态参数开箱即用:
:param路径段配合useParams即可读取 URL 参数,且与 React Router 语法完全兼容,可选段与 splat 模式同样支持; - TypeScript 类型安全:
Link组件与routes对象在编译期校验路径与参数,search/hash让链接构建更灵活; - 声明与文件保持同步:增删页面时,组件文件与
main.wasp中的声明必须同步维护。
下一步,就可以基于这份干净的骨架,按照教程继续实现 Entity、Query、Action 等核心功能(可参考 examples/tutorials/TodoApp/main.wasp.ts 中query、action与page(MainPage, { authRequired: true })的完整写法)。
【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考