
TanStack Router 如何用 useBlocker 阻止用户离开未保存表单的页面【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router在 React 应用里有一个很常见的坑用户在一个带表单的页面编辑到一半随手点了导航链接或浏览器后退表单内容直接丢失。TanStack Router 的useBlockerhook来自tanstack/react-router就是为这类场景设计的当导航发生时先执行你的拦截逻辑让用户确认「是否离开」确认后导航照常进行取消则所有待处理的导航被阻断。注意useBlocker目前的 API 在官方文档中标注为experimental见 useBlocker API 文档升级版本时留意其变化。useBlocker 拦截的是什么根据 Navigation Blocking 指南导航阻断分两层生效应用内导航由路由控制的导航点Link、navigate调用、前进后退等。每个 blocker 的shouldBlockFn会被异步、顺序地执行。任何一个 blocker 返回false即放行只要有一个返回true导航就被取消。beforeunload事件对路由管不到的页面卸载操作——关闭标签页/窗口、刷新——依赖浏览器的原生「Are you sure you want to leave?」对话框。用户确认则所有 blocker 被绕过取消则页面保持原样。所以useBlocker同时覆盖了「应用内跳转」和「刷新/关页」两条会丢数据的路径。最短路径用 window.confirm 拦截如果只是需要一个确认弹窗最快的写法是在shouldBlockFn里直接用window.confirm不需要 resolver。shouldBlockFn返回true表示拦截本次导航返回false表示放行这是 API 文档 中明确的语义import { useBlocker } from tanstack/react-router function MyComponent() { const [formIsDirty, setFormIsDirty] useState(false) useBlocker({ shouldBlockFn: () { if (!formIsDirty) return false const shouldLeave confirm(Are you sure you want to leave?) return !shouldLeave }, }) // ... }这里的formIsDirty是你在表单变更时维护的状态setFormIsDirty在输入/修改等地方调用即可。这个例子里不传withResolver默认false拦截结果完全由shouldBlockFn的返回值决定hook 返回void。自定义确认 UIwithResolver大多数实际项目会用与自身设计一致的弹窗或内联确认区这时用withResolver: true。开启后 hook 返回一个控制对象shouldBlockFn只负责判断「该不该弹确认」真正放行/取消由返回的proceed/reset完成注意withResolver为true时shouldBlockFn的返回值不会解决阻断见 指南import { useBlocker } from tanstack/react-router function MyComponent() { const [formIsDirty, setFormIsDirty] useState(false) const { proceed, reset, status, next } useBlocker({ shouldBlockFn: () formIsDirty, withResolver: true, }) return ( {/* 你的表单 */} {status blocked ( div pYou are navigating to {next.pathname}/p pAre you sure you want to leave?/p button onClick{proceed}Yes/button button onClick{reset}No/button /div )} / ) }返回值的含义API 文档statusblocked或idleblocked时next、current、action才有值分别给出目标位置、当前位置和触发导航的 actionproceed允许导航继续reset取消导航status复位为idle。shouldBlockFn的参数是类型安全的包含current和next两个位置对象各有routeId、fullPath、pathname、params、search以及action。可以用它做更精细的判断例如只在离开特定路由时拦截const { proceed, reset, status } useBlocker({ shouldBlockFn: ({ current, next }) { if ( current.routeId /editor-1 next.fullPath /foo/$id next.params.id 123 next.search.hello world ) { return true } return false }, enableBeforeUnload: false, withResolver: true, })上面这段与官方 navigation-blocking 示例 中根路由的拦截逻辑一致。控制浏览器的 beforeunload 弹窗enableBeforeUnload选项默认是true即始终拦截浏览器的beforeUnload事件。如果你只想在表单确实有改动时才弹原生确认框避免表单干净时刷新页面也弹窗可以传一个布尔值或函数useBlocker({ shouldBlockFn: () formIsDirty, enableBeforeUnload: formIsDirty, // or () formIsDirty })相关选项汇总均见 useBlocker API 文档shouldBlockFn必填返回boolean或Promisebooleandisabled可选默认false整体禁用该 blockerenableBeforeUnload可选默认trueboolean | (() boolean)withResolver可选默认falseblockerFn、condition已废弃deprecated新代码不要使用。跑一遍官方示例验证效果仓库里有一个完整示例 examples/react/navigation-blocking其中Editor1Component就是一个「输入框有内容即视为未保存」的未保存表单拦截场景源码见 main.tsx// Block leaving editor-1 if there is text in the input const { proceed, reset, next, current, status } useBlocker({ shouldBlockFn: () value ! , enableBeforeUnload: () value ! , withResolver: true, })按 示例 README 的步骤运行pnpm install pnpm devdev脚本实际执行的是vite --port 3000所以开发服务器起在 3000 端口。在浏览器里可以逐项验证进入 Editor 1 页面在输入框里输入文字点击「Go to Editor 2」或顶部指向其他路由的链接——页面停在原地出现「Are you sure you want to leave editor 1?」确认区并同时显示You are going from {current.pathname} to {next.pathname}点NOreset导航取消留在原页点YESproceed导航继续输入框为空时直接点链接不出现确认区导航直接通过有内容时刷新页面或关闭标签页出现浏览器原生确认对话框——这正是enableBeforeUnload: () value ! 在起作用。根路由上还挂了第二个 blocker只针对「从/editor-1导航到/foo/123?helloworld」这一条具体路径做拦截示例里点击顶栏的 foo 123 链接即可复现用来观察多个 blocker 并存的行为。替代写法与限制不想在逻辑里写 hook 的话可以用Block组件达到同样效果shouldBlockFn作为 prop 传入配合withResolver时以 render props 形式拿到{ status, proceed, reset }见 指南的 Component-based blocking 一节。应用内拦截由shouldBlockFn控制关页/刷新这类浏览器原生事件只能借助beforeunload的通用对话框无法在其中渲染自定义 UI。shouldBlockFn也可以返回Promiseboolean官方指南里展示了在函数内打开自己管理的 modal、等用户点击后再 resolve 的异步写法适合已有模态框管理的场景。参考Navigation Blocking 指南useBlocker API 参考navigation-blocking 示例源码手动搭建 React TanStack Router 项目如果你的项目还没引入 TanStack Router【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考