React 第四十三节 Router中 useBlocker 的使用详解及案例注意事项
前言
useBlocker
是 React Router
中用于阻止用户导航的钩子,它允许开发者在特定条件下(例如表单未保存时)拦截用户的导航行为(如点击链接、回退按钮等),并触发自定义逻辑(如显示确认对话框)。与 unstable_usePrompt 类似,但 useBlocker 提供更底层的控制能力。
注意:useBlocker 是实验性 API
一、useBlocker 核心用途
1.1、拦截导航行为:
阻止用户通过路由跳转、浏览器后退/前进按钮离开当前页面。
1.2、自定义确认逻辑:
灵活控制是否允许导航,并可结合弹窗组件实现更友好的交互。
1.3、异步处理:
支持在用户确认后执行异步操作(如保存数据)再允许导航。
二、useBlocker 基本使用
import { useBlocker } from "react-router-dom";function EditForm() {const [isDirty, setIsDirty] = useState(false);// 使用 useBlocker 拦截导航const blocker = useBlocker(({ currentLocation, nextLocation }) => isDirty && currentLocation.pathname !== nextLocation.pathname);// 当拦截被触发时,显示确认对话框useEffect(() => {if (blocker.state === "blocked") {const confirm = window.confirm("您有未保存的更改,确定要离开吗?");if (confirm) {blocker.proceed(); // 用户确认离开,放行导航} else {blocker.reset(); // 用户取消,重置拦截状态}}}, [blocker.state]);return (<form><input type="text" onChange={(e) => setIsDirty(e.target.value !== "")}/></form>);
}
三、useBlocker参数说明
useBlocker
接收一个函数作为参数,该函数返回 true 时触发拦截:
useBlocker((navigation: Navigation) => boolean
);
navigation 对象
:包含导航的详细信息:
currentLocation
:当前路由位置。
nextLocation
:目标路由位置。
formData
:如果是表单提交导航,包含表单数据。
formMethod
:表单的 HTTP 方法(如 “post”)。
3.1、返回对象
useBlocker
返回一个 Blocker 对象,包含以下属性:
state: String类型字符串 ,拦截状态,
值为:“unblocked
”(未拦截)、“blocked
”(已拦截)、“proceeding
”(正在放行)
proceed(): 回调函数() => void: 手动放行被拦截的导航
reset(): 回调函数() => void: 重置拦截状态
四、useBlocker完整案例:自定义弹窗拦截
4.1、useBlocker 定义拦截逻辑
import { useBlocker } from "react-router-dom";
import { useState } from "react";
import ConfirmationModal from "./ConfirmationModal"; // 自定义弹窗组件function UserProfileEditor() {const [isDirty, setIsDirty] = useState(false);const blocker = useBlocker(({ currentLocation, nextLocation }) => {return isDirty && currentLocation.pathname !== nextLocation.pathname;});// 处理弹窗确认/取消const handleConfirm = async () => {// 可选:在放行前保存数据await saveData();blocker.proceed();};const handleCancel = () => {blocker.reset();};return (<><form><input type="text" onChange={(e) => setIsDirty(e.target.value !== "")}/></form>{/* 自定义弹窗 */}<ConfirmationModalisOpen={blocker.state === "blocked"}message="未保存的更改将丢失,确定离开?"onConfirm={handleConfirm}onCancel={handleCancel}/></>);
}
4.2、 useBlocker 自定义弹窗组件 (ConfirmationModal)
function ConfirmationModal({ isOpen, message, onConfirm, onCancel }) {if (!isOpen) return null;return (<div className="modal-overlay"><div className="modal"><p>{message}</p><button onClick={onConfirm}>离开</button><button onClick={onCancel}>取消</button></div></div>);
}
五、useBlocker 使用注意事项
5.1、兼容性
useBlocker
是 React Router 的实验性 API
(可能在 v6.x 中标为 unstable_useBlocker),未来版本可能调整 API 或行为。
需使用 React Router v6.4+ 并启用数据路由(createBrowserRouter
)。
5.2、拦截范围
只能拦截 客户端路由导航(如 <Link>、navigate()
),无法阻止页面刷新或关闭(需配合 useBeforeUnload
)。
useBeforeUnload 详细介绍分析
示例:同时处理路由跳转和页面关闭:
// 拦截路由跳转
useBlocker(shouldBlock);// 拦截页面关闭/刷新
useBeforeUnload(() => {if (shouldBlock) return "确认离开?";
});
5.3、useBlocker性能优化
避免在拦截条件函数中执行高开销操作(如复杂计算、API 请求),应快速返回布尔值。
与表单的交互
使用 <Form>
提交时,默认会绕过 useBlocker。如需拦截表单提交,需手动处理:
const submitHandler = (e) => {e.preventDefault();if (isDirty) {showConfirmationModal(() => {e.target.submit(); // 用户确认后提交});}
};
5.4、useBlocker 重置状态
导航被拦截后,必须调用 proceed() 或 reset()
,否则应用会卡在阻塞状态。
六 、useBlocker 与 unstable_usePrompt 的对比
总结
useBlocker
是处理复杂导航拦截需求的强大工具,适合需要自定义交互
(如美观弹窗)或异步操作
的场景。
注意:其实验性状态和浏览器限制,建议在关键流程(如数据丢失防护)中结合 useBeforeUnload
实现全覆盖拦截。