React 第四十九节 Router中useNavigation的具体使用详解及注意事项

前言

useNavigationReact 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 返回一个包含以下属性的对象

React 第四十九节 Router中useNavigation的具体使用详解及注意事项_第1张图片

四、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>
  );
}

总结

useNavigationReact Router 中用于增强用户体验的关键钩子,通过它开发者可以:

1.精确感知导航状态(空闲、加载中、提交中

2.根据状态动态调整 UI(显示加载指示器、禁用按钮等)

3.提前预知用户即将访问的页面

4.创建更加流畅的导航体验

合理使用 useNavigation 可以显著提升应用的交互质量和用户满意度,特别是在需要处理异步操作和页面过渡的场景中。

你可能感兴趣的:(React,react.js,javascript,前端)