前言
useNavigation
是 React Router
中一个强大的钩子,用于获取当前页面导航的状态信息。
它可以帮助开发者根据导航状态优化用户体验,如显示加载指示器、防止重复提交等。
一、useNavigation核心用途
检测导航状态:判断当前是否正在进行页面导航或数据加载
防止用户操作冲突:在导航过程中禁用表单提交按钮
优化用户体验:在页面加载期间显示加载指示器
预加载感知:感知即将发生的导航并提前准备
二、useNavigation 基本用法
import { useNavigation } from "react-router-dom";
function NavigationStatus() {
const navigation = useNavigation();
return (
<div>
<p>当前导航状态: {navigation.state}</p>
<p>目标路径: {navigation.location?.pathname || "无"}</p>
</div>
);
}
三、useNavigation 返回值详解
useNavigation 返回一个包含以下属性的对象:
四、useNavigation 导航状态详解
"idle"
:没有导航活动
"loading"
:正在加载新页面(页面跳转中)
"submitting"
:正在提交表单数据
五、useNavigation 完整代码案例
5.1、全局加载指示器
import { useNavigation } from "react-router-dom";
function GlobalLoadingIndicator() {
const navigation = useNavigation();
// 当有导航活动时显示加载指示器
const isLoading = navigation.state !== "idle";
return isLoading ? (
<div className="loading-overlay">
<div className="spinner"></div>
{navigation.state === "submitting" && (
<p>提交数据中...</p>
)}
{navigation.state === "loading" && (
<p>加载页面中...</p>
)}
</div>
) : null;
}
5.2、表单提交状态管理
import { useNavigation } from "react-router-dom";
function SubmitButton() {
const navigation = useNavigation();
const isSubmitting = navigation.state === "submitting";
return (
<button
type="submit"
disabled={isSubmitting}
className={isSubmitting ? "submitting" : ""}
>
{isSubmitting ? "提交中..." : "提交表单"}
</button>
);
}
function ContactForm() {
return (
<form method="post" action="/contact">
<input type="text" name="name" placeholder="姓名" required />
<input type="email" name="email" placeholder="邮箱" required />
<textarea name="message" placeholder="留言" rows={4} required />
<SubmitButton />
</form>
);
}
5.3、基于导航状态优化用户体验
import { useNavigation } from "react-router-dom";
function ProductPage() {
const navigation = useNavigation();
// 当即将导航到新页面时,显示骨架屏
const isNavigating = navigation.state === "loading";
const targetIsProduct = navigation.location?.pathname?.startsWith("/product/");
return (
<div className="product-container">
{isNavigating && targetIsProduct ? (
<ProductSkeleton />
) : (
<ProductDetails />
)}
<RelatedProducts />
{/* 在提交评论时禁用评论表单 */}
<CommentForm disabled={navigation.state === "submitting"} />
</div>
);
}
function ProductSkeleton() {
return (
<div className="skeleton">
<div className="skeleton-image"></div>
<div className="skeleton-title"></div>
<div className="skeleton-description"></div>
</div>
);
}
六、useNavigation 高级用法:预加载感知
import { useNavigation, Link } from "react-router-dom";
function ProductList({ products }) {
const navigation = useNavigation();
// 获取即将导航到的产品ID
const nextProductId = navigation.location?.pathname?.split("/")[2];
return (
<div>
<h2>产品列表</h2>
<ul>
{products.map(product => (
<li key={product.id}>
<Link to={`/product/${product.id}`}>
{product.name}
{/* 高亮即将访问的产品 */}
{nextProductId === product.id && " (正在加载...)"}
</Link>
</li>
))}
</ul>
</div>
);
}
七、useNavigation
与相似钩子的对比
钩子 用途 返回信息
useNavigation
:用于 获取当前导航状态、目标位置等
useLocation
:用于 获取当前URL信息,返回信息包含:当前路径、查询参数等
useNavigate
:用于 编程式导航,返回:导航函数
useLoaderData
:用于 获取路由加载器提供的数据,返回: 加载的数据
useActionData
: 用于 获取表单提交后返回的数据,返回: 动作返回的数据
八、注意事项
8.1、理解状态变化:
"submitting" → "loading" → "idle"
是典型的状态变化流程
表单提交后会立即跳转到新页面
8.2、避免过度使用:
只在需要响应导航状态的组件中使用
避免在性能敏感
的组件中使用
8.3、与数据加载的配合:
useNavigation
关注导航状态
useLoaderData
关注数据加载结果
两者可以配合使用优化加载体验
8.4、错误处理:
function SmartButton() {
const navigation = useNavigation();
const actionData = useActionData();
const isSubmitting = navigation.state === "submitting";
const hasError = actionData?.error;
return (
<button
type="submit"
disabled={isSubmitting || hasError}
>
{isSubmitting ? "处理中..." : "提交"}
</button>
);
}
九、最佳实践
9.1、 创建导航感知组件
function NavigationAwareLink({ to, children }) {
const navigation = useNavigation();
const isActive = navigation.location?.pathname === to;
const isNavigatingTo = navigation.state === "loading" &&
navigation.location?.pathname === to;
return (
<Link
to={to}
className={`nav-link
${isActive ? "active" : ""}
${isNavigatingTo ? "navigating" : ""}`}
>
{children}
{isNavigatingTo && <span className="loading-dot"></span>}
</Link>
);
}
9.2、 结合 Suspense
优化加载体验
import { useNavigation } from "react-router-dom";
import { Suspense } from "react";
function Dashboard() {
const navigation = useNavigation();
return (
<div>
<h1>控制面板</h1>
<Suspense fallback={<Spinner />}>
{navigation.state === "idle" ? (
<DashboardContent />
) : (
<DashboardSkeleton />
)}
</Suspense>
</div>
);
}
总结
useNavigation
是 React Router
中用于增强用户体验的关键钩子,通过它开发者可以:
1.精确感知导航状态(空闲、加载中、提交中
)
2.根据状态动态调整 UI
(显示加载指示器、禁用按钮等)
3.提前预知用户
即将访问的页面
4.创建更加流畅的导航体验
合理使用 useNavigation
可以显著提升应用的交互质量和用户满意度,特别是在需要处理异步操作和页面过渡的场景中。