如何知道React应用中的react-router可以返回以显示后退按钮

35

似乎没有API方法可以检测应用程序中当前页面是否可以返回。可以检查历史记录长度,但其中包括前进和后退堆栈。

我希望只在用户确实可以返回时显示返回按钮。

5个回答

21

如果您有一个位置密钥,那么可以检查location.key,这意味着您是在应用内进行路由。但如果没有,那就意味着您来自应用外部,或者只是在新标签页中打开了应用等。

import { useHistory, useLocation } from "react-router-dom";
const history = useHistory();
const location = useLocation();

<Button
  onClick={() => {
    if (location.key) {
      history.goBack();
    }
  }}
  disabled={!location.key}
/>;

针对 V6 及更新版本:

import { useHistory, useLocation } from "react-router-dom";
const history = useHistory();
const location = useLocation();

<Button
  onClick={() => {
    if (location.key !== 'default') {
      history.goBack();
    }
  }}
  disabled={location.key === 'default'}
/>;

1
+1,这对我有用,虽然我希望能够获得一些文档,明确说明新打开的选项卡将始终具有 NULL 键。 - John M Gant
3
注意:使用最新版本的 React Router V6 时,您需要检查 "default" 而不是空字符串。现在您的初始位置是 "default" 而不是 ""。请阅读 API 参考文档:https://github.com/remix-run/history/blob/main/docs/api-reference.md#location - Lars Flieger

12

如果history.action的值为POP,那么你可以通过检查它来确定是否有可返回的路由。这是我发现的唯一方法。

<Button
  onClick={() => {
    if (history.action !== 'POP') history.goBack();
  }}
  disabled={history.action === 'POP'}
/>

5
action 属性指定了路由器最后一次的操作,它与历史堆栈中剩余的项没有任何关系。 - ahmadkarimi12
1
如果用户刷新页面,它将返回到“POP”。因此,在这种情况下它不起作用。 - Heidi
这对我来说很合适。 - Eduin Garcia Cordero

3

我想我找到了一个解决方法。

有一个 onpopstate 事件

调用 history.pushState() 或 history.replaceState() 不会触发 popstate 事件。只有通过执行浏览器操作(例如单击后退按钮(或在 JavaScript 中调用 history.back()))在两个相同文档的历史记录条目之间导航时,才会触发 popstate 事件。

我已经检查过了:React Router 在状态中保存了一个 key 属性: 在历史访问期间,它可能包含像这样的数据: event.state: {key: "jr2go2", state: undefined}

当我们返回到进入网站或应用程序的最后一页时,此状态属性将为 null: event.state: null 因此,我们可以使用 redux + rxjs(例如)来处理它,如下所示:

// epic
export const handleHistoryWalkEpic = () =>
  fromEvent<PopStateEvent>(window, 'popstate')
  .pipe(
    map(event => setCanGoBack(!!event.state)),
  )

// reducer
case NavigationBarActionsTypes.SET_CAN_GO_BACK:
  return {
    ...state,
    canGoBack: action.payload.canGoBack,
  }

当进行任何推进历史记录的操作时,您应该将canGoBack设置为true,这是可能的,可以使用任何路由处理程序组件:

componentWillUpdate(nextProps: any) {
    let { location } = this.props;

    if (nextProps.history.action === 'PUSH') {
      this.props.setCanGoBack()
    }
}

-1

您可以通过检查location.history是否大于2来实现。

以下是一个示例,用于在您的应用程序中显示或隐藏返回按钮:

onBack={ history.length > 2 ? () => { history.goBack() } : null }

2
为什么特别是 2 - ed'
1
@EdwardSammutAlessi 如果历史记录长度只有1,那意味着你还没有在堆栈中导航,因此你无法返回。只有当堆栈至少有2个元素时,才能在堆栈导航中返回。这对你有意义吗? - diogopalhais
5
这不是一个解决方案。假设您打开了第一页(history.length为1),然后转到下一页2(history.length为2),再次转到页面3(history.length为3)。现在,当您从第三页回到第一页时,history.length仍然是3,但在第一页上,您无法返回任何页面。 - Dmitriy Vinokurov
1
我发现如果我打开一个新的Chrome标签并转到一个页面,history.length始终为2。 - daihovey
但是如果你返回,history.length 不会减少。 - Zach Smith

-4

它使用 this.props.location.action 返回 'POP' 和 'PUSH' 的值


如果我们向后移动,它会执行“POP”操作,这样您就可以检测到它。 - Mohit Verma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接