# chitu-react **Repository Path**: ansiboy/chitu-react ## Basic Information - **Project Name**: chitu-react - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-22 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # maishu-chitu-react 用 [chitu.js](https://github.com/ansiboy/chitu) 替换 react-router 的**兼容层**: 业务代码里 `import { ... } from 'react-router' / 'react-router-dom'` 基本不用改, 底层路由与页面管理由 chitu 的 `PageMaster` 承担。 > 兼容层实现的是**目标项目实际用到的 react-router 子集**(见下方「已实现 / 未实现」), > 并非 react-router v6 的全部 API;`path="*"` 这类写法需按本文的模板语法调整。 > 自本版本起,本包**只提供 react-router 兼容层**。 > 不再导出 chitu 原生用法的 `Application` / `PageProps` / `dataLoader` —— 需要旧 API 的项目请锁定旧版本。 ## 特性 - **声明式路由零改动**:`` / `` / `` / `` / `` / `` 与 react-router 同形。 - **真正的嵌套 Outlet**:每个 `` 挂一个 chitu `PageMaster`,布局外壳始终挂载,只有子页面切换显隐。 - **干净的 URL**:地址栏就是 `/admin/users` 这类 pathname,不会被改写成 chitu 的 pageName 形式;一次导航 = 一条 history 记录。 - **页面级缓存与卸载**:chitu 按路由缓存页面(`display:none` 切换),页面关闭时自动 `root.unmount()` 清理副作用。 - **路径模板与 node-shop-v2 同源**:底层用 `path-to-regexp`(express 风格),支持 `:id`、花括号可选段 `{/:page}`、`/:page.css`、`{*splat}` 通配等。 - **单一产物**:整个包只有一份实现(`dist/index.*`),不存在多入口各带一份 context 的隐患。 ## 安装 ```bash npm install maishu-chitu-react maishu-chitu react react-dom ``` > `maishu-chitu`(`>=5.0.0`)、`react` / `react-dom`(`>=18.3`)为对等依赖。 > 兼容层本身不依赖 `maishu-chitu` 的 `Application`,只使用 `PageMaster`。 ## 接入 ```ts // 直接用包名,不再需要 react-router / react-router-dom import { BrowserRouter, Routes, Route, Outlet, Link, NavLink } from 'maishu-chitu-react'; ``` 旧项目迁移时把说明符批量替换即可(`from "react-router"` / `from "react-router-dom"` → `from "maishu-chitu-react"`)。 用 importmap 的项目只需映射 `maishu-chitu-react` 与 `maishu-chitu` 两项。 > `.`、`./react-router`、`./react-router-dom` 三个入口都指向**同一份** `dist/index.*`, > 混用也不会出现「两份 React context」的问题(因此 `maishu-chitu-react/react-router` 这类旧写法仍可用)。 ## 用法 ```tsx import { BrowserRouter, Routes, Route, Outlet, Link, NavLink, useParams, useLocation, useNavigate, useSearchParams, generatePath, } from 'maishu-chitu-react'; function Layout() { return (
首页 商品 {/* 子路由渲染在这里 —— 布局本身不会被重新挂载 */}
); } createRoot(document.getElementById('root')!).render( }> } /> } /> } /> }> } /> } /> {/* catch-all:path-to-regexp 的通配写法(不支持 react-router 的裸 `*`) */} } /> , ); ``` ### 已实现 / 未实现 **已实现**(即目标项目当前使用的全部符号): | 类型 | API | | --- | --- | | 组件 | `BrowserRouter` `Routes` `Route` `Outlet` `Link` `NavLink` | | Hooks | `useParams` `useLocation` `useNavigate` `useSearchParams` | | 函数 | `generatePath` | | 类型 | `LinkProps` `NavLinkProps` `NavigateFunction` `Location` | **未实现**(v6 的其余 API):`Navigate`、`useRoutes`、`useMatch`、`createBrowserRouter` / `RouterProvider`、`MemoryRouter`、`HashRouter`、`useOutletContext`、`useNavigationType`、`Prompt` 等。 用到这些的业务代码需要自行改造。 **需要改写的写法**:catch-all 的 `` 在本兼容层里要写成 `` (通配内容读 `useParams().splat`;若需连 `/` 也命中则写 `"{*splat}"`)—— 因为底层是 path-to-regexp,它不接受 react-router 的裸 `*`。 **行为差异**:`useLocation()` 的 `hash` / `state` / `key` 为近似实现;`generatePath` 默认对参数值做 `encodeURIComponent`(react-router v6 不编码)。 ## 路由模板(path-to-regexp 语法) | 写法 | 含义 | | --- | --- | | `/product/:id` | 动态段,`useParams().id` | | `/product-list{/:pageIndex}` | 可选段(无值时整段省略) | | `/{home}` | 可选**字面量**段(既匹配 `/` 也匹配 `/home`) | | `/{:page}` | 花括号内的参数 | | `/:page.css` | 带字面量后缀的参数 | | `*splat` | 通配(catch-all),**至少一段**,`useParams().splat` 读取内容 | | `{*splat}` | 通配且**可为空** —— 等价 react-router 的 `*`(能匹配 `/` 本身),做 404 兜底请用这个 | > 模板必须是 path-to-regexp v8 语法:**不支持** react-router 的 `:id?`(写 `{/:id}`)与裸 `*`(写 `{*splat}`; > 注意 `*splat` 是「必填」,根路径不会命中,别拿它当 404 兜底)。 > 迁移已有项目时把这些写法改掉即可;服务端若也用 v8(如本项目配套的 node-shop-v2),两边模板可保持一致。 > 参数生成(`generatePath`)与匹配同源:必填段缺值抛错,通配段按 `/` 切分后拼接。 ## 页面生命周期与性能 - 页面按路由**缓存**(同一路由换参数不会新建节点),DOM 节点数 = 路由种类数。 - 隐藏页面通过 `display:none` 切换,**不参与布局与绘制**,仅占用内存。 - 页面**关闭**时 React `root` 会 `unmount()`,组件卸载并清理副作用。 - 隐藏(未关闭)页面的 React 副作用仍可能后台运行,请在组件 `useEffect` 中做好清理。 ## 开发 ```bash npm run build # esbuild 打包 dist(cjs + mjs)+ tsc 生成类型声明 npm run start # 启动本地 demo(PORT 环境变量,默认 8080) npm test # jest 运行测试(jsdom 环境) ``` > demo 见 `demo/rr-main.tsx`:两级嵌套 Outlet、动态参数、query 读写、返回、catch-all, > 面板会显示外壳挂载时间戳与浏览器地址栏,用于验证「外壳保持挂载 / 地址栏未被改写」。 ## 许可证 [MIT](./LICENSE)