React Router Framework 模式导航全攻略:Link、NavLink、Form、redirect 与 useNavigate 📅 发布时间:2026/9/8 19:09:06 👁 浏览次数: React Router Framework 模式导航全攻略Link、NavLink、Form、redirect 与 useNavigate【免费下载链接】react-routerDeclarative routing for React项目地址: https://gitcode.com/GitHub_Trending/re/react-router本篇指南基于 React Router 官方教程 docs/start/framework/navigating.md 展开全面讲解 Framework 模式下用户导航应用的 5 种核心手段NavLink带激活/挂起状态的高亮导航、Link普通客户端路由链接、Form携带用户数据提交的导航表单、redirectloader/action 内的服务端重定向以及useNavigate程序化导航兜底 Hook。读完你将能够依据不同交互场景正确选用导航 API并结合路由数据层loader/action、pending 状态与渐进增强原理写出健壮的导航代码。引言一次点击背后的多种导航手段在 React Router 的 Framework 模式即包含 loader、action、渲染的服务端/数据路由能力下用户从 A 页面到 B 页面这件事可以由五类 API 触发NavLink需要根据当前路由状态渲染激活active或挂起pending样式的导航链接Link不需要激活态样式、仅需普通跳转的链接Form需要把用户输入表单字段作为导航一部分提交时使用redirect在 route loader 或 action 内部代码逻辑上需要将用户重定向到其它 URLuseNavigate非用户交互驱动、纯代码触发的程序化导航。这五种 API 在源码层实现位置集中在 packages/react-router/lib/dom/lib.tsxLink、NavLink、Form 组件与 packages/react-router/lib/router/router.ts导航状态机下文会逐一展开并结合源码说明其原理与适用场景。NavLink带激活与挂起状态的高亮导航NavLink专为需要渲染 active/pending 状态的导航链接设计典型场景是页面顶部的全局导航栏。基础用法如下import { NavLink } from react-router; export function MyAppNav() { return ( nav NavLink to/ end Home /NavLink NavLink to/trending end Trending Concerts /NavLink NavLink to/concertsAll Concerts/NavLink NavLink to/accountAccount/NavLink /nav ); }注意到 Home 与 Trending Concerts 都带上了end属性它表示当 URL 与to完全相同而不是前缀匹配时才判定为激活。例如没有end时/account这个链接会在用户访问/account/settings时仍处于激活态而加了end后/只有在精确命中根路径时才高亮避免根链接在任意子路径下都被点亮。默认类名与 CSS 样式NavLink会为不同状态渲染默认的类名你可以直接用纯 CSS 完成样式定制a.active { color: red; } a.pending { animate: pulse 1s infinite; } a.transitioning { /* css transition is running */ }这三种类名对应三个独立状态源码中它们的判定逻辑在 NavLink 实现中非常清晰active当前location.pathname等于或在前缀匹配规则下以边界字符起始于to解析出的路径pending当前正处于一次导航中且目标路径routerState.navigation.location与to匹配——也就是说页面尚未切换完成时该链接已先行标亮transitioning目标路径命中且启用了 View Transitions API。在源码中当className不是函数时默认类名是按以下顺序拼接的见 lib.tsx L1706-L1714className [ classNameProp, isActive ? active : null, isPending ? pending : null, isTransitioning ? transitioning : null, ] .filter(Boolean) .join( );同时isActive时默认渲染aria-currentpage属性可通过aria-currentprop 覆盖有助于无障碍辅助技术识别当前所在页面。回调式 className / style / children内联样式与条件渲染除默认类名外NavLink的className、style、children三个 prop 都支持传入回调函数回调会收到{ isActive, isPending, isTransitioning }三个布尔状态从而支持内联样式或条件渲染// className按状态拼接多个类 NavLink to/messages className{({ isActive, isPending, isTransitioning }) [ isPending ? pending : , isActive ? active : , isTransitioning ? transitioning : , ].join( ) } Messages /NavLink// style按状态返回内联样式对象甚至可以设置 viewTransitionName NavLink to/messages style{({ isActive, isPending, isTransitioning }) { return { fontWeight: isActive ? bold : , color: isPending ? red : black, viewTransitionName: isTransitioning ? slide : , }; }} Messages /NavLink// children把状态传给渲染函数实现激活时附带指示图标等场景 NavLink to/tasks {({ isActive, isPending, isTransitioning }) ( span className{isActive ? active : }Tasks/span )} /NavLink结合 pending-ui.md 中局部挂起指示的最佳实践你完全可以在回调里拿到isPending后立刻为即将发生的跳转渲染一个Spinner让局部 UI 比整页转场更早给出反馈。NavLink 更多可配置项从源码确认查看 NavLink 组件签名 可知除end外还支持caseSensitive路径大小写敏感匹配默认关闭、relativeroute 或 path 两种相对解析模式以及viewTransition为本次导航开启 View Transition此时isTransitioning才有意义。NavLink内部本质上是把解析好的状态与aria-current转发给Link渲染。Link当导航链接不需要激活态样式如果链接不需要基于当前路由的激活态样式直接使用Link即可。它是对原生a href的渐进增强封装JavaScript 加载后拦截点击走客户端路由无整页刷新未加载时则退化为标准锚点跳转。import { Link } from react-router; export function LoggedOutMessage() { return ( p Youve been logged out.{ } Link to/loginLogin again/Link /p ); }Link的to可以是一个字符串也可以是一个包含pathname/search/hash的部分路径对象Link to{{ pathname: /some/path, search: ?querystring, hash: #hash, }} /Framework 模式下Link还额外承担两类增强能力详见 Link 组件 API 文档懒加载路由发现discover默认render链接一渲染就提前发现目标路由模块设为none则仅在实际点击时才去发现适用于关闭 路由雾Fog of War 类预发现的开销预取prefetch取值none默认/intent悬停或聚焦时预取/render渲染即预取/viewport进入视口时预取移动端常用。预取通过插入link relprefetch标签实现——也因此如果 CSS 里用了nav :last-child选择器需要改为:last-of-type避免预取标签影响末位元素样式。其它常用开关还包括replace替换历史栈当前条目而非压栈、state写入持久化 location state服务端不可见、reloadDocument强制整页文档导航、preventScrollReset配合ScrollRestoration时阻止滚动重置以及viewTransitionView Transitions API。是否使用这些扩展能力请对照当前项目所用模式framework/data/declarative确认见 Link.md 中各 prop 标注的[modes: ...]。Form把用户输入变成一次导航Form组件用于携带用户输入的URLSearchParams进行导航。最常见的 GET 提交即搜索表单Form action/search input typetext nameq / /Form当用户在输入框里键入journey并提交后浏览器/客户端路由会导航到/search?qjourney也就是说Form methodget的行为与原生 HTML form 完全一致把各控件的name/value序列化为查询字符串拼到actionURL 上。而Form methodpost同样会导航到action指向的路由但提交载荷是FormData而不是URLSearchParams从而能够命中该路由的action函数执行数据变更。实操建议向服务端/action POST 数据时更常见、更推荐的做法是改用useFetcher()即fetcher.Form因为普通Form methodpost会引发一次全局导航而 fetcher 拥有独立的加载状态不会把用户从当前页面带走。具体用法参见 使用 FetchersUsing Fetchers。渐进增强JS 加载前后的两级体验从 Form 组件文档 可知Form是原生form的渐进增强封装JavaScript 尚未加载时浏览器自己接管提交与 pending 状态比如旋转的 favicon服务端渲染的页面在基础层面已可用JS 加载后React Router 接管提交通过 fetch 把数据交给 action并在 useNavigation 中激活 pending 状态进而支持提交完成后的全页面数据自动 revalidate保证 UI 与数据一致。相关机制背景见 progressive-enhancement.md。需要留意的一个细节原生form只支持get和post两种 methodForm虽支持delete/patch/put但如果想保留上述无 JS 的基础可用性应避免使用这些扩展动词。Form 常用属性速查action提交目标 URL缺省时默认指向最近的已匹配路由本身methodget导航 URLSearchParams/post导航 FormData 提交给 action等encType默认application/x-www-form-urlencoded文件上传时用multipart/form-datanavigate{false}跳过导航、改用内部 fetcher 提交等价于不关心返回数据的fetcher.Form简写replace提交后替换历史栈当前条目防止用户点返回又回到带表单的页面reloadDocument强制整页文档提交而非客户端路由 fetchviewTransition/preventScrollReset语义与Link同名属性一致。redirect在 loader 与 action 中做服务端式重定向在 route 的 loader 和 action 内部你通常无法让用户点击某个Link——用户请求进来后代码要先做鉴权、数据查询等逻辑再决定渲染什么。此时应返回一个redirect让路由层接管跳转。最经典的场景是未登录则送回登录页import { redirect } from react-router; export async function loader({ request }) { let user await getUser(request); if (!user) { return redirect(/login); } return { userName: user.name }; }同样常见的是数据创建完成后跳转到新纪录详情页PRG 模式Post/Redirect/Getimport { redirect } from react-router; export async function action({ request }) { let formData await request.formData(); let project await createProject(formData); return redirect(/projects/${project.id}); }用户提交新建项目表单 →action被调用并创建记录 → 返回redirect→ 浏览器地址与页面跳到/projects/新id同时因为这是一次 GET 导航刷新页面不会重复提交表单。redirect 的底层实现与状态码redirect本质上返回的是一个携带Location头的 redirectResponse默认状态码为 302 Found。其处理路径在 router.ts路由状态机在收集到 loader/action 的返回结果后调用findRedirect识别出这种响应见 router.ts L2549-L2564随后进入startRedirectNavigation从响应的Location头解析目标地址并启动一次新的导航见 router.ts L3286-L3288。几个值得记录的实现细节默认以REPLACE替换历史栈条目的方式导航因此用户按返回不会退回触发重定向的中间页面需要保留历史记录时可显式使用replace: false的ResponseInit变体API 文档对redirect的第二个参数init支持传入状态码或ResponseInit由于redirect接受绝对 URL、可导航到外部域名凡是用户输入可能进入重定向目标时应用自身应做好校验文档有时也会写成throw redirect(/login)在错误边界语境下用 throw 中断执行流更符合声明式风格用法细节见 redirect API 文档。useNavigate留给非交互式场景的程序化导航useNavigate返回一个导航函数允许代码在没有用户点击的情况下把用户带到新页面import { useNavigate } from react-router; export function useLogoutAfterInactivity() { let navigate useNavigate(); useFakeInactivityHook(() { navigate(/logout); }); }官方对它的定位非常克制——这个 Hook 的使用应当少见并建议在可行时优先使用本指南中的其它 API。原因在于声明式 APILink/NavLink/Form把导航意图直接写进了 UI 结构更容易被搜索引擎、测试与后续维护者理解而命令式的navigate()散落在事件处理与副作用里可读性和可追踪性都更差。useNavigate应当保留给那些用户并没有在执行交互、但程序必须发起导航的场景例如用户长时间无操作后自动登出如上例计时器驱动型 UI如倒计时结束跳转的测验页面其它任何由时钟、推送、后台任务等外部事件触发的跳转。如果导航时机需要被拦截/确认例如表单未保存时阻止离开或需要更细粒度的控制可以进一步了解 useNavigate 的完整签名以及 导航拦截navigation blocking 一节中基于 block 机制的实现。小结五种导航 API 的选型对照场景首选 API关键点顶部导航 / 侧边导航需高亮当前项NavLinkend控制精确匹配className/style/children支持状态回调正文里的普通跳转链接Link纯客户端导航Framework 模式可选prefetch/discover/viewTransition把表单输入变成 URL 查询参数Form methodget提交后导航到/search?qjourney提交数据给 action 并留在原地useFetcher()的fetcher.Form独立状态、不引起全局导航详见 fetchersloader 未登录/无权限、action 创建完跳转详情redirect默认 302 REPLACE 语义需校验外部 URL超时登出、计时 UI 等非交互跳转useNavigate仅少数场景使用优先声明式 API导航只是起点——当用户真的点下这些链接或提交表单后页面往往需要立即展示 pending/乐观 UI 以维持响应感这部分内容可继续阅读同系列教程 Pending UI挂起与乐观界面。而五种导航手段对应的 loader/action 数据流与完整路由模块结构则在 路由模块route module 中系统介绍。【免费下载链接】react-routerDeclarative routing for React项目地址: https://gitcode.com/GitHub_Trending/re/react-router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考