使用 useCallbackPrompt 和 useBlocker 掌握 React 中的导航控制

在现代网络应用中,打造无缝导航体验至关重要。无论您是保护未保存的更改还是确认关键操作,控制导航流程都能确保更好的用户体验。

本文介绍了**useCallbackPrompt**,一个基于**useBlocker**构建的自定义 React hook,它通过可自定义的提示提供对导航事件的增强控制。

React Route Blocker

什么是 useCallbackPrompt?

`useCallbackPrompt` 是一个自定义钩子,旨在拦截导航事件并在允许用户离开之前显示确认提示。它使用较低级别的 **useBlocker** 钩子构建,该钩子与 React Router 的内部导航 API 集成。

什么是 useBlocker?

`useBlocker` 是一个实用钩子,它通过监听 React Router 的导航事件来提供核心阻止机制。它允许在尝试导航时创建自定义逻辑。

以下是 useBlocker 的代码:

import { useContext, useEffect } from 'react';
import { UNSAFE_NavigationContext } from 'react-router-dom';

const useBlocker = (blocker, enable = true) => {
  const navigator = useContext(UNSAFE_NavigationContext).navigator;

  useEffect(() => {
    if (!enable) return;

    const unblock = navigator.block((tx) => {
      const autoUnblockingTx = {
        ...tx,
        retry() {
          unblock();
          tx.retry();
        },
      };

      blocker(autoUnblockingTx);
    });

    return unblock;
  }, [navigator, blocker, enable]);
};

export default useBlocker;

useCallbackPrompt 的工作原理

`useCallbackPrompt` 扩展了 `useBlocker`,为管理导航提示提供了更加用户友好的界面。

实现如下:

import { useCallback, useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router';
import useBlocker from './useBlocker';

const useCallbackPrompt = (enable) => {
  const navigate = useNavigate();
  const location = useLocation();
  const [showPrompt, setShowPrompt] = useState(false);
  const [lastLocation, setLastLocation] = useState(null);
  const [confirmedNavigation, setConfirmedNavigation] = useState(false);

  // Cancel the navigation
  const cancelNavigation = useCallback(() => {
    setShowPrompt(false);
  }, []);

  // Block navigation and show prompt
  const handleBlockedNavigation = useCallback(
    (nextLocation) => {
      if (
        !confirmedNavigation &&
        nextLocation?.location?.pathname !== location?.pathname
      ) {
        setShowPrompt(true);
        setLastLocation(nextLocation);
        return false;
      }
      return true;
    },
    [confirmedNavigation, location]
  );

  // Confirm the navigation
  const confirmNavigation = useCallback(() => {
    setShowPrompt(false);
    setConfirmedNavigation(true);
  }, []);

  useEffect(() => {
    if (confirmedNavigation && lastLocation) {
      navigate(lastLocation.location.pathname);
      setConfirmedNavigation(false);
    }
  }, [confirmedNavigation, lastLocation, navigate]);

  useBlocker(handleBlockedNavigation, enable);

  return [showPrompt, confirmNavigation, cancelNavigation];
};

export default useCallbackPrompt;

使用 useCallbackPrompt 的优点

  • 可定制的提示:导航对话框的完全可定制的 UI。
  • 动态控制:根据条件轻松启用或禁用导航阻止。
  • 重试机制:确认后自动重试被阻止的导航。
  • 无缝集成:与 React Router 的导航 API 配合使用,实现现代 SPA。
  • 如何使用 useCallbackPrompt

    以下是如何在 React 应用中使用 `useCallbackPrompt` 的方法:

    1.安装 React Router

    确保 React Router 已安装:

    npm install react-router-dom

    2. 使用钩子

    以下是一个表单示例,当用户离开且未保存更改时会显示提示:

    import React, { useState } from 'react';
    import useCallbackPrompt from './useCallbackPrompt';
    
    const FormPage = () => {
      const [isDirty, setIsDirty] = useState(false);
      const [showPrompt, confirmNavigation, cancelNavigation] = useCallbackPrompt(isDirty);
    
      return (
        <>
          
    setIsDirty(true)} placeholder="Type something..." />
    {showPrompt && (

    You have unsaved changes. Do you really want to leave?

    )} ); }; export default FormPage;

    3. 自定义模态框

    您可以使用自己最喜欢的 UI 库(例如,Material-UI、TailwindCSS)中的设计替换模态框。

    使用案例

  • 表单保护防止用户意外离开未保存更改的页面。
  • 关键操作在执行删除数据等破坏性操作之前确认。
  • 路由守卫根据身份验证或其他应用程序状态动态阻止导航。
  • 结论

    `useCallbackPrompt` 和 `useBlocker` 是管理 React 应用程序中导航的宝贵工具。通过将 React Router 的导航 API 与自定义逻辑相结合,您可以构建优先考虑安全性和可用性的强大用户体验。