当前位置: 首页 > news >正文

React 中除了react-router还有哪些路由方案

在用React开发时,常用的路由是react-router ,但除此之外,还有两个路由方案,因为他们具备 react-router 没有的特性。

1. @tanstack/router

1.1. 主要特性

  • 100% 推断的 TypeScript 支持

  • 类型安全的导航

  • 嵌套路由和布局路由

  • 内置的路由加载器,带有 SWR 缓存

  • 为客户端数据缓存设计(如 TanStack Query、SWR 等)

  • 自动路由预取

  • 异步路由元素和错误边界

  • 基于文件的路由生成

  • 类型安全的 JSON 优先搜索参数状态管理 API

  • 路径和搜索参数模式验证

  • 搜索参数导航 API

  • 自定义搜索参数解析器/序列化器支持

  • 搜索参数中间件

  • 路由匹配/加载中间件

1.2. 基础使用示例

import React, { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'
import {Outlet,RouterProvider,Link,createRouter,createRoute,createRootRoute} from '@tanstack/react-router'import { TanStackRouterDevtools } from '@tanstack/router-devtools'const rootRoute = createRootRoute({component: () => (<><div className="p-2 flex gap-2"><Link to="/" className={[&.active]:font-bold">Home</Link>{' '}<Link to="/about" className={[&.active]:font-bold">About</Link></div><hr /><Outlet /><TanStackRouterDevtools /></>),
})const indexRoute = createRoute({getParentRoute: () => rootRoute,path: '/',component: function Index() {return (<div className="p-2"><h3>Welcome Home!</h3></div>)},
})const aboutRoute = createRoute({getParentRoute: () => rootRoute,path: '/about',component: function About() {return <div className="p-2">Hello from About!</div>},
})const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
const router = createRouter({ routeTree })declare module '@tanstack/react-router' {interface Register {router: typeof router}
}const rootElement = document.getElementById('app')!
if (!rootElement.innerHTML) {const root = ReactDOM.createRoot(rootElement)root.render(<StrictMode><RouterProvider router={router} /></StrictMode>,)
}

1.3. 原理浅析

@tanstack/router 的实现原理与 react-router 类似,关注的概念也完全相同,可以理解为它站在 react-router 的肩膀上,在某些细节上做了增强。

历史记录的实现:https://github.com/TanStack/router/blob/main/packages/history/src/index.ts

Router 入口:https://github.com/TanStack/router/blob/main/packages/react-router/src/link.tsx

2. wouter

2.1. 主要特性

  • 最小依赖,压缩后仅 2.1 KB,对比 React Router 的 18.7 KB。

  • 同时支持 React 和 Preact。

  • 没有顶级的 <Router /> 组件,它是完全可选的。

  • 模仿 React Router 的最佳实践,提供熟悉的 Route、Link、Switch 和 Redirect 组件。

  • 拥有基于 hook 的 API,用于更细粒度地控制路由:useLocation、useRoute 和 useRouter。

2.2. 基础使用示例

import { Link, Route, Switch } from "wouter";const App = () => (<><Link href="/users/1">Profile</Link><Route path="/about">About Us</Route>{/* Routes below are matched exclusively - the first matched route gets rendered*/}<Switch><Route path="/inbox" component={InboxPage} /><Route path="/users/:name">{(params) => <>Hello, {params.name}!</>}</Route>{/* Default route in a switch */}<Route>404: No such page!</Route></Switch></>
);

2.3. 原理浅析

对于不同路由历史与定位信息的封装。

  • https://github.com/molefrog/wouter/blob/v3/packages/wouter/src/use-browser-location.js

  • https://github.com/molefrog/wouter/blob/v3/packages/wouter/src/use-hash-location.js

  • https://github.com/molefrog/wouter/blob/v3/packages/wouter/src/memory-location.js

import { parse as parsePattern } from "regexparam";
import {useBrowserLocation,useSearch as useBrowserSearch,
} from "./use-browser-location.js";
import {useRef,useContext,createContext,isValidateElement,cloneElement,createElement as h,Fragment,forwardRef,useIsomorphicLayoutEffect,useEvent,
} from "./react-deps.js";
import { absolutePath, relativePath, unescape, stripQm } from "./paths.js";// 定义默认的 Router 对象
const defaultRouter = {hook: useBrowserLocation,searchHook: useBrowserSearch,parser: parsePattern,base: "",ssrPath: undefined,ssrSearch: undefined,hrefs: (x) => x,
};// 创建一个 Router 上下文,提供给应用中的其他部分使用
const RouterCtx = createContext(defaultRouter);// 获取最近的父级 router
export const useRouter = () => useContext(RouterCtx);// 创建一个参数上下文,提供给 `useParams()` 使用,以获取匹配的参数
const ParamsCtx = createContext({});
export const useParams = () => useContext(ParamsCtx);// 内部版本的 useLocation 函数,避免多余的 useRouter 调用
const useLocationFromRouter = (router) => {const [location, navigate] = router.hook(router);return [unescape(relativePath(router.base, location)),useEvent((to, navOpts) => navigate(absolutePath(to, router.base), navOpts)),];
};// 使用 useRouter 获取当前的 location
export const useLocation = () => useLocationFromRouter(useRouter());// 获取当前搜索参数并返回
export const useSearch = () => {const router = useRouter();return unescape(stripQm(router.searchHook(router)));
};// 路由匹配函数
export const matchRoute = (parser, route, path, loose) => {const { pattern, keys } =route instanceof RegExp? { keys: false, pattern: route }: parser(route || "*", loose);const result = pattern.exec(path) || [];const [base, ...matches] = result;return base !== undefined? [true,() => {const groups =keys !== false? Object.fromEntries(keys.map((key, i) => [key, matches[i]])): result.groups;let obj = { ...matches };groups && object.assign(obj, groups);return obj;},...(loose ? [$base] : []),]: [false, null];
};// 使用 useRouter 获取路由,并匹配路径
export const useRoute = (pattern) =>matchRoute(useRouter().parser, pattern, useLocation()[0]);// Router 组件,用于提供自定义路由上下文
export const Router = ({ children, ...props }) => {const parent_ = useRouter();const parent = props.hook ? defaultRouter : parent_;let value;const [path, search] = props.ssrPath?.split("?") ?? [];if (search) (props.ssrSearch = search), (props.ssrPath = path);props.hrefs = props.hrefs ?? props.hook?.hrefs;let ref = useRef({}),prev = ref.current,next = prev;for (let k in parent) {const option =k === "base"? parent[k] + (props[k] || ""): props[k] || parent[k];if (prev === next && option !== next[k]) {ref.current = next = { ...next };}next[k] = option;if (option !== parent[k]) value = next;}return h(RouterCtx.Provider, { value, children });
};// 渲染 Route 组件,根据 props 提供不同渲染逻辑
const h_route = ({ children, component }, params) => {if (component) return h(component, { params });return typeof children === "function" ? children(params) : children;
};// Route 组件,用于匹配路径并渲染对应组件
export const Route = ({ path, nest, match, ...renderProps }) => {const router = useRouter();const [location] = useLocationFromRouter(router);const [matches, params, base] =match ?? matchRoute(router.parser, path, location, nest);if (!matches) return null;const children = base? h(Router, { base }, h_route(renderProps, params)): h_route(renderProps, params);return h(ParamsCtx.Provider, { value: params, children });
};
http://www.xdnf.cn/news/1045783.html

相关文章:

  • 深度学习——基于卷积神经网络实现食物图像分类【2】(数据增强)
  • Office Word MCP 使用指南(小白版)
  • PCB设计教程【大师篇】stm32开发板PCB布线(电源部分)
  • 最近的一些思考与总结-优化版
  • qt信号与槽--02
  • XR-RokidAR-UXR3.0-Draggable 脚本解析
  • 如何高效的学习算法与数据结构
  • React 实现砸金蛋游戏
  • webpack+vite前端构建工具 - 1为什么要构建工具 2webpack基础配置
  • Nginx全面深入学习目录
  • gradle在build时时如何知道要去扫描Realm相关的数据模型类的?
  • 4.查看、删除数据库
  • 数据库核心技术深度剖析:事务、索引、锁与SQL优化实战指南(第五节)----数据库事务
  • LeetCode第 454 场周赛题解
  • 【git】如何在team里使用公共账号进行ssh clone
  • leetcode25-K个一组翻转链表
  • 【Zephyr 系列 27】自定义 Shell 命令框架:打造自己的控制台命令系统
  • 数据结构 排序
  • 【狂飙AGI】第6课:前沿技术-文生图(系列2)
  • 无人机仿真时在px4包外自己的工作空间中编辑px4有关launch文件的方法
  • 小记:把react项目从web迁移到electron
  • ubuntu 22.04 安装部署elk(elasticsearch/logstash/kibana) 7.10.0详细教程
  • 【嵌入式ARM汇编基础】-快速了解ARM汇编语言
  • vSphere环境证书更新/续订案例及注意事项
  • 【CompletableFuture】基础Future (一)
  • 大模型笔记5:Agent
  • 大模型笔记2:提示词工程
  • 鸿蒙运动开发实战:打造专属运动视频播放器
  • SpringBoot新闻项目学习day2-前后端搭建以及数据查询(分页查询)
  • 「Linux文件及目录管理」文件内容的显示和处理类命令