Javascript 在 React-router 中拦截/处理浏览器的后退按钮?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39342195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Intercept/handle browser's back button in React-router?
提问by high incompetance
I'm using Material-ui's Tabs, which are controlled and I'm using them for (React-router) Links like this:
我正在使用 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"/>} />
If I'm currenlty visting dashboard/data and I click browser's back button I go (for example) to dashboard/users but the highlighted Tab still stays on dashboard/data (value=2)
如果我正在访问仪表板/数据并单击浏览器的后退按钮,我会(例如)转到仪表板/用户,但突出显示的选项卡仍保留在仪表板/数据上(值 = 2)
I can change by setting state, but I don't know how to handle the event when the browser's back button is pressed?
我可以通过设置状态来改变,但是我不知道当浏览器的后退按钮被按下时如何处理事件?
I've found this:
我发现了这个:
window.onpopstate = this.onBackButtonEvent;
but this is called each time state is changed (not only on back button event)
但每次更改状态时都会调用它(不仅在后退按钮事件上)
采纳答案by high incompetance
here is how I ended up doing it:
这是我最终这样做的方式:
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})
}
}
}
thanks everybody for helping lol
谢谢大家帮助哈哈
回答by Jay Shin
This is a bit old question and you've probably already got your answer, but for people like me who needed this, I'm leaving this answer.
这是一个有点老的问题,你可能已经得到了答案,但是对于像我这样需要这个的人,我要留下这个答案。
Using react-router made the job simple as such:
使用 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();
}
回答by brogrammer
Version 3.x of the React Router API has a set of utilitiesyou can use to expose a "Back" button event before the event registers with the browser's history. You must first wrap your component in the withRouter()
higher-order component. You can then use the setRouteLeaveHook()
function, which accepts any route
object with a valid path
property and a callback function.
React Router API 的 3.x 版有一组实用程序,可用于在事件注册到浏览器历史记录之前公开“返回”按钮事件。您必须首先将您的组件包装在withRouter()
高阶组件中。然后您可以使用该setRouteLeaveHook()
函数,该函数接受route
具有有效path
属性和回调函数的任何对象。
import {Component} from 'react';
import {withRouter} from 'react-router';
class Foo extends Component {
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave);
}
routerWillLeave(nextState) { // return false to block navigation, true to allow
if (nextState.action === 'POP') {
// handle "Back" button clicks here
}
}
}
export default withRouter(Foo);
回答by Bnaya
Hooks sample
挂钩样品
const { history } = useRouter();
useEffect(() => {
return () => {
if (history.action === "POP") // && history.location.pathname === "any specific path") {
history.replace(history.location.pathname, /* the new state */);
}
};
}, [history])
I don't use history.listen because it doesn't affect the state
我不使用 history.listen 因为它不影响状态
const disposeListener = history.listen(navData => {
if (navData.pathname === "/props") {
navData.state = /* the new state */;
}
});
回答by Nicolas Keller
Using hooks you can detect the back and forward buttons
使用钩子可以检测后退和前进按钮
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, ])
回答by Irmantas Ramanauskas
I used withrouter hoc in order to get history prop and just write a componentDidMount() method:
我使用 withrouter hoc 来获取历史道具并只编写一个 componentDidMount() 方法:
componentDidMount() {
if (this.props.history.action === "POP") {
// custom back button implementation
}
}
回答by vinzbruce
It depends on the type of Router you use in React.
这取决于你在 React 中使用的路由器类型。
If you use BrowserRouter from react-router (not available in react-router v4 though), as mentioned above, you can use the action 'POP' to intercept the browser back button.
如果您使用 react-router 中的 BrowserRouter(不过在 react-router v4 中不可用),如上所述,您可以使用“POP”操作来拦截浏览器的后退按钮。
However, if you use HashRouter to push the routes, above solution will not work. The reason is hash router always triggered with 'POP' action when you click browser back button or pushing the route from your components. You cant differentiate these two actions either with window.popstate or history.listen simply.
但是,如果您使用 HashRouter 推送路由,则上述解决方案将不起作用。原因是当您单击浏览器后退按钮或从组件推送路由时,哈希路由器总是通过“POP”操作触发。您不能简单地使用 window.popstate 或 history.listen 区分这两个操作。
回答by Andy
Most of the answers for this question either use outdated versions of React Router, rely on less-modern Class Components, or are confusing; and none use Typescript, which is a common combination. Here is an answer using Router v5, function components, and Typescript:
这个问题的大部分答案要么使用过时的 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.
}
}
})
}
A fuller example with explanations can be found here.
可以在此处找到更完整的示例和说明。
回答by Aman Singh
You can use "withrouter" HOC and use this.props.history.goBack
.
您可以使用“withrouter” HOC 并使用this.props.history.goBack
.
<Button onClick={this.props.history.goBack}>
BACK
</Button>