【问题标题】:React Router v.6 usePrompt TypeScriptReact Router v.6 usePrompt TypeScript
【发布时间】:2022-06-20 14:50:37
【问题描述】:

我基本上是在尝试拦截路由更改。也许与 React Router v6 中 vue 的 beforeEach 等效的东西可能会很有用,因为 React Router v.6 包含 usePrompt

在每次路由更改之前,我想做一些逻辑 - 逻辑可能需要根据结果中断甚至更改最终路由。

我已经四处搜索,但我真的找不到解决这个特定问题的东西。

提前致谢。

【问题讨论】:

  • react-router/react-router-dom 没有这个功能。您能否提供 Vue 代码的 minimal and complete code example,以及您尝试在 React 中进行类似操作的尝试,我们可以提供帮助吗?
  • @DrewReese 我无法提供示例。基本上我想在用户尝试离开特定路线时显示模式/警报。似乎在带有 Prompt/Blocker 的 react-router v5 中是可能的
  • 我明白了。是的,目前该功能已从 RRDv6 中排除(据说它将返回,待定),但我想您可以使用 custom router & history object 复制接近它的内容以侦听路由更改,特别是 POP操作,可能与监听beforeunload 事件结合使用。

标签: reactjs react-router react-router-dom


【解决方案1】:

目前他们已经从 react-router v6 中删除了 usePrompt

我从 ui.dev 找到了一个解决方案并添加了 TypeScript 支持,现在我正在使用它,直到 react-router 恢复 usePrompt/useBlocker 钩子

import { History, Transition } from 'history';
import { useCallback, useContext, useEffect } from "react";
import { UNSAFE_NavigationContext as NavigationContext } from "react-router-dom";

type ExtendNavigator = Navigator & Pick<History, "block">;
export function useBlocker(blocker: (tx: Transition) => void, when = true) {
    const { navigator } = useContext(NavigationContext);

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

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

            blocker(autoUnblockingTx);
        });

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

export default function usePrompt(message: string, when = true) {
    const blocker = useCallback((tx: Transition) => {
        if (window.confirm(message)) tx.retry();
    }, [message]);

    useBlocker(blocker, when);
}

然后可以在任何您希望“A 你确定要离开吗?”的视图/组件中使用 - 当条件为真时显示消息。

usePrompt("Do you want to leave?", isFormDirty());

【讨论】:

    【解决方案2】:

    是的 usePromptuseBlock 已被删除,但您可以使用 history.block 实现相同的效果,这是在 React Router Dom V5 中使用带有自定义模式的 history.block 阻止导航的工作示例

    import { useHistory } from "react-router-dom";
    import { UnregisterCallback } from "history";
    ...
    
    type Prop = {
      verify?: {
        blockRoute?: (nextRoute: string) => boolean;
      }
    };
    
    ...
    // in the component where you want to show confirmation modal on any nav change
    
    const history = useHistory();
    const unblock = useRef<UnregisterCallback>();
    const onConfirmExit = () => {
      /**
       * if user confirms to exit, we can allow the navigation
       */
    
      // Unblock the navigation.
      unblock?.current?.();
      // Proceed with the blocked navigation
      goBack();
    };
    
    useEffect(() => {
      /**
       * Block navigation and register a callback that
       * fires when a navigation attempt is blocked.
       */
      unblock.current = history.block(({ pathname: to }) => {
       /**
        * Simply allow the transition to pass immediately,
        * if user does not want to verify the navigate away action,
        * or if user is allowed to navigate to next route without blocking.
        */
       if (!verify || !verify.blockRoute?.(to)) return undefined;
    
       /**
        * Navigation was blocked! Let's show a confirmation dialog
        * so the user can decide if they actually want to navigate
        * away and discard changes they've made in the current page.
        */
       showConfirmationModal();
       // prevent navigation
       return false;
    });
    
    // just in case theres an unmount we can unblock if it exists
      return unblock.current;
    }, [history]);
    
    

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 2021-05-10
      • 2017-12-05
      • 2017-10-22
      相关资源
      最近更新 更多