【问题标题】:How to go back one page only if the page is within the site in React Router Dom?如何仅当页面在 React Router Dom 的站点内时返回一页?
【发布时间】:2023-01-26 14:15:06
【问题描述】:

我想创建一个“返回”按钮,如果该页面在站点内,则该按钮仅返回一页。

我试过关注 this answer 添加返回按钮:

import { useNavigate } from 'react-router-dom';

function YourApp() {
  const navigate = useNavigate();

  return (
    <>
      <button onClick={() => navigate(-1)}>go back</button>
    </>
  );
}

但即使页面不在站点内,它也会返回一页。

例如:如果我打开一个选项卡,转到 stackoverflow.com,然后转到我的页面并单击“返回”按钮,我将返回到 StackOverflow。

如果上一页不在站点内,我如何让它将我发送到默认页面?

【问题讨论】:

  • 这是预期的行为。带有 delta 参数的 navigate 函数仅在历史堆栈中向前/向后导航。因为这个堆栈没有暴露给你的通过 RRD 编写代码,您需要保留和维护自己的历史堆栈,并在堆栈为空时有条件地处理后退导航。也就是说,将用户困在您的页面/应用程序中通常被认为是糟糕的 UI/UX。
  • @drew-reese 我不同意在应用程序中使用“返回”按钮将用户带到同一个应用程序是一种不好的做法。我认为这是预期的行为。
  • 对……我觉得叫它“回去”有点误导。如果我点击“返回”按钮并且回到我之前的地方,那是一次糟糕的经历。实际上,我现在正在研究一个可能的解决方案/演示。
  • @drew-reese 我的意思是,我认为当应用程序中没有上一页时,将按钮的标签更改为“转到 <page>”可能会更好。 OTOH,我认为用户可以说,如果他们在 URL 栏中键入 mysite.com/pages/create 并且页面中有一个返回按钮,这并不意味着“返回到以前的网站”。

标签: reactjs react-router-dom


【解决方案1】:

我最终通过在 Redux 中创建一个 history 数组并在它发生变化时从 useLocation 向它提供当前位置来解决这个问题:

export const MyRoutes = () => {
  const location = useLocation();
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(pushLocationToHistory(location));
  }, [location]);
};

然后我可以只使用最后一项的路径(如果可用)。

【讨论】:

    【解决方案2】:

    基本要点是您可以保留和维护自己的历史堆栈并检查是否有历史条目可以返回。如果堆栈为空,则重定向到应用程序的主页,否则,允许正常导航。

    使用 React 上下文保存堆栈状态并提供自定义的 navigate 函数的示例。

    import {
      createContext,
      useCallback,
      useContext,
      useEffect,
      useState
    } from "react";
    import {
      useNavigate as useNavigateBase,
      UNSAFE_NavigationContext,
      NavigationType
    } from "react-router-dom";
    
    const NavigateContext = createContext({
      navigate: () => {},
    });
    
    const useNavigate = () => useContext(NavigateContext);
    
    const NavigateProvider = ({ children }) => {
      const [historyStack, setHistoryStack] = useState([]);
    
      const navigateBase = useNavigateBase();
    
      const { navigator } = useContext(UNSAFE_NavigationContext);
    
      useEffect(() => {
        const listener = ({ location, action }) => {
          switch (action) {
            case NavigationType.Push:
              return setHistoryStack((stack) => stack.concat(location));
    
            case NavigationType.Replace:
              return setHistoryStack((stack) =>
                stack.slice(0, -1).concat(location)
              );
    
            case NavigationType.Pop:
              return setHistoryStack((stack) => stack.slice(0, -1));
    
            default:
            // ignore
          }
        };
    
        return navigator.listen(listener);
      }, [navigator]);
    
      useEffect(() => {
        console.log({ historyStack });
      }, [historyStack]);
    
      const navigate = useCallback(
        (arg, options) => {
          if (typeof arg === "number" && arg < 0 && !historyStack.length) {
            navigateBase("/", { replace: true });
          } else {
            navigateBase(arg, options);
          }
        },
        [historyStack, navigateBase]
      );
    
      return (
        <NavigateContext.Provider value={navigate}>
          {children}
        </NavigateContext.Provider>
      );
    };
    

    用法示例:

    const GoBackButton = () => {
      const navigate = useNavigate();
      return <button onClick={() => navigate(-1)}>go back</button>
    }
    

    ...

    function App() {
      return (
        <NavigateProvider>
          ... app code ...
        </NavigateProvider>
      );
    }
    

    【讨论】:

      猜你喜欢
      • 2022-12-03
      • 2018-12-21
      • 2022-07-19
      • 2020-07-09
      • 2022-07-10
      • 1970-01-01
      • 1970-01-01
      • 2023-01-14
      • 2022-07-28
      相关资源
      最近更新 更多