在 React-router 中拦截/处理浏览器的后退按钮?

IT技术 javascript reactjs react-router material-ui
2021-01-29 14:11:27

我正在使用 Material-ui 的选项卡,这些选项卡是受控的,我将它们用于 (React-router) 链接,如下所示:

    <Tab value={0} label="dashboard" containerElement={<Link to="/dashboard/home"/>}/>
    <Tab value={1} label="users" containerElement={<Link to="/dashboard/users"/>} />
  <Tab value={2} label="data" containerElement={<Link to="/dashboard/data"/>} />

如果我正在访问仪表板/数据并单击浏览器的后退按钮,我会(例如)转到仪表板/用户,但突出显示的选项卡仍保留在仪表板/数据上(值 = 2)

我可以通过设置状态来改变,但是我不知道当浏览器的后退按钮被按下时如何处理事件?

我发现了这个:

window.onpopstate = this.onBackButtonEvent;

但每次更改状态时都会调用它(不仅在后退按钮事件上)

6个回答

这是一个有点老的问题,你可能已经得到了答案,但对于像我这样需要这个的人,我要留下这个答案。

使用 react-router 使工作变得简单:

import { browserHistory } from 'react-router';

componentDidMount() {
    super.componentDidMount();

    this.onScrollNearBottom(this.scrollToLoad);

    this.backListener = browserHistory.listen(location => {
      if (location.action === "POP") {
        // Do your stuff
      }
    });
  }

componentWillUnmount() {
    super.componentWillUnmount();
    // Unbind listener
    this.backListener();
}
从 react-router@5.0.0 开始,您无法browserHistory按照此回复中的说明进行导入似乎history包含在props传递给从路由引用的任何组件中。如果不完全正确,请随时纠正我。
2021-03-14 14:11:27
@loopmode 当您处理后退按钮操作时,您使用类似browserHistory.goBack()??
2021-03-18 14:11:27
我发现在其他地方,一位同事正在手动干预历史记录,类似 if (nextLocation.action === 'POP' && getStepIndex(nextLocation.pathname) === 0) { browserHistory.push({pathname: ${getPathForIndex(0)}} ); 返回假;所以..if POP then PUSH为了使前进按钮不可用(它会在没有提交表单的情况下继续前进)所以..你的答案仍然正确 - 我这边的用户错误:)
2021-04-06 14:11:27
对我不起作用。使用 react-router@3.0.5,location.action 总是 PUSH,即使点击浏览器后退按钮
2021-04-09 14:11:27
对于任何使用 React Router 4+ 的人来说,listen 有 2 个参数,location 和 action。 history.listen((loc, action) => if (action === 'POP') // do stuff)
2021-04-12 14:11:27

使用钩子可以检测后退和前进按钮

import { useHistory } from 'react-router-dom'


const [ locationKeys, setLocationKeys ] = useState([])
const history = useHistory()

useEffect(() => {
  return history.listen(location => {
    if (history.action === 'PUSH') {
      setLocationKeys([ location.key ])
    }

    if (history.action === 'POP') {
      if (locationKeys[1] === location.key) {
        setLocationKeys(([ _, ...keys ]) => keys)

        // Handle forward event

      } else {
        setLocationKeys((keys) => [ location.key, ...keys ])

        // Handle back event

      }
    }
  })
}, [ locationKeys, ])
这仍然是处理前后的好方法还是添加了任何东西来处理可以说的hackylocationKeys, setLocationKeys位?然而。请。
2021-03-19 14:11:27
到目前为止,是的,这是我们拥有的最佳解决方案。
2021-03-20 14:11:27
@ShabbirEssaji 它使用析构和扩展运算符,返回一个删除了第一个元素的数组。这可能有帮助
2021-03-31 14:11:27
@ShabbirEssaji 您现在可能已经找到了答案,但是当必须分配变量但不会使用变量时,通常会使用下划线。
2021-04-01 14:11:27
setLocationKeys(([ _, ...keys ]) => keys) 中的_(下划线)是什么
2021-04-08 14:11:27

这是我最终这样做的方式:

componentDidMount() {
    this._isMounted = true;
    window.onpopstate = ()=> {
      if(this._isMounted) {
        const { hash } = location;
        if(hash.indexOf('home')>-1 && this.state.value!==0)
          this.setState({value: 0})
        if(hash.indexOf('users')>-1 && this.state.value!==1)
          this.setState({value: 1})
        if(hash.indexOf('data')>-1 && this.state.value!==2)
          this.setState({value: 2})
      }
    }
  }

谢谢大家帮助哈哈

这不是一种反应方式
2021-04-03 14:11:27
“反应方式”是过度限制和拜占庭式的。
2021-04-07 14:11:27

挂钩样品

const {history} = useRouter();
  useEffect(() => {
    return () => {
      // && history.location.pathname === "any specific path")
      if (history.action === "POP") {
        history.replace(history.location.pathname, /* the new state */);
      }
    };
  }, [history])

我不使用 history.listen 因为它不影响状态

const disposeListener = history.listen(navData => {
        if (navData.pathname === "/props") {
            navData.state = /* the new state */;
        }
    });
我只能useRouter()useHooks库中找到一个函数usehooks.com/useRouter
2021-03-24 14:11:27
不是useRouter()特定于 Next.js 框架的吗?
2021-03-26 14:11:27
我会将依赖数组更改为 [history.location, history.action] 因为它不会捕获位置更改
2021-04-05 14:11:27

这个问题的大多数答案要么使用过时的 React Router 版本,要么依赖不太现代的类组件,要么令人困惑;并且都没有使用 Typescript,这是一种常见的组合。这是使用 Router v5、函数组件和 Typescript 的答案:

// use destructuring to access the history property of the ReactComponentProps type
function MyComponent( { history }: ReactComponentProps) {

    // use useEffect to access lifecycle methods, as componentDidMount etc. are not available on function components.
    useEffect(() => {

        return () => {
            if (history.action === "POP") {
                // Code here will run when back button fires. Note that it's after the `return` for useEffect's callback; code before the return will fire after the page mounts, code after when it is about to unmount.
                }
           }
    })
}

可以在此处找到更完整的示例和说明