Bar*_*aes 74 reactjs react-router
我希望我的ReactJS应用程序在导航离开特定页面时通知用户.特别是弹出消息,提醒他/她做一个动作:
"更改已保存,但尚未发布.现在就这样做吗?"
我应该react-router
全局触发这个,还是可以从反应页面/组件中完成?
我没有在后者身上找到任何东西,我宁愿避开第一个.除非它当然是标准,但这让我想知道如何做这样的事情,而不必将代码添加到用户可以去的每个其他可能的页面..
欢迎任何见解,谢谢!
jca*_*ady 91
react-router
v4引入了一种阻止导航的新方法Prompt
.只需将其添加到您要阻止的组件:
import { Prompt } from 'react-router'
const MyComponent = () => (
<React.Fragment>
<Prompt
when={shouldBlockNavigation}
message='You have unsaved changes, are you sure you want to leave?'
/>
{/* Component JSX */}
</React.Fragment>
)
Run Code Online (Sandbox Code Playgroud)
这将阻止任何路由,但不会阻止页面刷新或关闭.要阻止它,您需要添加它(根据需要使用适当的React生命周期进行更新):
componentDidUpdate = () => {
if (shouldBlockNavigation) {
window.onbeforeunload = () => true
} else {
window.onbeforeunload = undefined
}
}
Run Code Online (Sandbox Code Playgroud)
onbeforeunload有浏览器的各种支持.
Shu*_*tri 31
在react-router v2.4.0
或更高版本之前和之前v4
有几个选项
<Route
path="/home"
onEnter={ auth }
onLeave={ showConfirm }
component={ Home }
>
Run Code Online (Sandbox Code Playgroud)
您可以在离开带有挂钩的路线之前阻止转换发生或提示用户.
const Home = withRouter(
React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave)
},
routerWillLeave(nextLocation) {
// return false to prevent a transition w/o prompting the user,
// or return a string to allow the user to decide:
// return `null` or nothing to let other hooks to be executed
//
// NOTE: if you return true, other hooks will not be executed!
if (!this.state.isSaved)
return 'Your work is not saved! Are you sure you want to leave?'
},
// ...
})
)
Run Code Online (Sandbox Code Playgroud)
请注意,此示例使用了withRouter
引入的高阶组件v2.4.0.
但是,手动更改URL中的路径时,这些解决方案并不完美
在某种意义上说
要react-router v4
使用提示或自定义历史记录:
但是,在fromactact-router react-router v4
的帮助下,它更容易实现Prompt
根据文件
提示
用于在离开页面之前提示用户.当您的应用程序进入一个应该阻止用户导航的状态时(就像表格填写完整一样),渲染一个
<Prompt>
.Run Code Online (Sandbox Code Playgroud)import { Prompt } from 'react-router' <Prompt when={formIsHalfFilledOut} message="Are you sure you want to leave?" />
消息:字符串
用户在尝试离开时提示用户的消息.
Run Code Online (Sandbox Code Playgroud)<Prompt message="Are you sure you want to leave?"/>
消息:func
将使用用户尝试导航到的下一个位置和操作进行调用.返回一个字符串以向用户显示提示,或返回true以允许转换.
Run Code Online (Sandbox Code Playgroud)<Prompt message={location => ( `Are you sure you want to go to ${location.pathname}?` )}/>
什么时候:布尔
<Prompt>
您可以随时渲染它而不是有条件地渲染后卫,而是通过when={true}
或when={false}
防止或允许相应的导航.
在您的渲染方法中,您只需根据需要添加文档中提到的内容.
更新:
如果您希望在使用离开页面时要执行自定义操作,则可以使用自定义历史记录并将路由器配置为
history.js
import createBrowserHistory from 'history/createBrowserHistory'
export const history = createBrowserHistory()
...
import { history } from 'path/to/history';
<Router history={history}>
<App/>
</Router>
Run Code Online (Sandbox Code Playgroud)
然后在你的组件中你可以使用history.block
like
import { history } from 'path/to/history';
class MyComponent extends React.Component {
componentDidMount() {
this.unblock = history.block(targetLocation => {
// take your action here
return false;
});
}
componentWillUnmount() {
this.unblock();
}
render() {
//component render here
}
}
Run Code Online (Sandbox Code Playgroud)
act*_*eek 23
对于react-router
2.4.0+
注意:建议将所有代码迁移到最新代码react-router
以获取所有新的好东西.
按照react-router文档中的建议:
应该使用withRouter
更高阶的组件:
我们认为这个新的HoC更好更容易,并将在文档和示例中使用它,但切换并不是一项艰难的要求.
作为文档中的ES6示例:
import React from 'react'
import { withRouter } from 'react-router'
const Page = React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, () => {
if (this.state.unsaved)
return 'You have unsaved information, are you sure you want to leave this page?'
})
}
render() {
return <div>Stuff</div>
}
})
export default withRouter(Page)
Run Code Online (Sandbox Code Playgroud)
小智 8
对于react-router
v3.x
我遇到了同样的问题,我需要对页面上任何未保存更改的确认消息。在我的例子中,我使用的是React Router v3,所以我不能使用<Prompt />
,它是从React Router v4引入的。
我处理“后退按钮点击”和“意外的链接点击”用的组合setRouteLeaveHook
和history.pushState()
,并办理“刷新按钮”与onbeforeunload
事件处理程序。
setRouteLeaveHook ( doc ) & history.pushState ( doc )
仅使用 setRouteLeaveHook 是不够的。出于某种原因,尽管单击“后退按钮”时页面保持不变,但 URL 已更改。
// setRouteLeaveHook returns the unregister method
this.unregisterRouteHook = this.props.router.setRouteLeaveHook(
this.props.route,
this.routerWillLeave
);
...
routerWillLeave = nextLocation => {
// Using native 'confirm' method to show confirmation message
const result = confirm('Unsaved work will be lost');
if (result) {
// navigation confirmed
return true;
} else {
// navigation canceled, pushing the previous path
window.history.pushState(null, null, this.props.route.path);
return false;
}
};
Run Code Online (Sandbox Code Playgroud)onbeforeunload (文档)
它用于处理“意外重新加载”按钮
window.onbeforeunload = this.handleOnBeforeUnload;
...
handleOnBeforeUnload = e => {
const message = 'Are you sure?';
e.returnValue = message;
return message;
}
Run Code Online (Sandbox Code Playgroud)以下是我编写的完整组件
this.props.router
.this.props.route
是从调用组件传递下来的请注意,currentState
作为道具传递以具有初始状态并检查任何更改
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { withRouter } from 'react-router';
import Component from '../Component';
import styles from './PreventRouteChange.css';
class PreventRouteChange extends Component {
constructor(props) {
super(props);
this.state = {
// initialize the initial state to check any change
initialState: _.cloneDeep(props.currentState),
hookMounted: false
};
}
componentDidUpdate() {
// I used the library called 'lodash'
// but you can use your own way to check any unsaved changed
const unsaved = !_.isEqual(
this.state.initialState,
this.props.currentState
);
if (!unsaved && this.state.hookMounted) {
// unregister hooks
this.setState({ hookMounted: false });
this.unregisterRouteHook();
window.onbeforeunload = null;
} else if (unsaved && !this.state.hookMounted) {
// register hooks
this.setState({ hookMounted: true });
this.unregisterRouteHook = this.props.router.setRouteLeaveHook(
this.props.route,
this.routerWillLeave
);
window.onbeforeunload = this.handleOnBeforeUnload;
}
}
componentWillUnmount() {
// unregister onbeforeunload event handler
window.onbeforeunload = null;
}
handleOnBeforeUnload = e => {
const message = 'Are you sure?';
e.returnValue = message;
return message;
};
routerWillLeave = nextLocation => {
const result = confirm('Unsaved work will be lost');
if (result) {
return true;
} else {
window.history.pushState(null, null, this.props.route.path);
if (this.formStartEle) {
this.moveTo.move(this.formStartEle);
}
return false;
}
};
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
PreventRouteChange.propTypes = propTypes;
export default withRouter(PreventRouteChange);
Run Code Online (Sandbox Code Playgroud)如果有任何问题,请告诉我:)
这就是当用户切换到另一个路由或离开当前页面并转到另一个 URL 时显示消息的方式
import PropTypes from 'prop-types'
import React, { useEffect } from 'react'
import { Prompt } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
const LeavePageBlocker = ({ when }) => {
const { t } = useTranslation()
const message = t('page_has_unsaved_changes')
useEffect(() => {
if (!when) return () => {}
const beforeUnloadCallback = (event) => {
event.preventDefault()
event.returnValue = message
return message
}
window.addEventListener('beforeunload', beforeUnloadCallback)
return () => {
window.removeEventListener('beforeunload', beforeUnloadCallback)
}
}, [when, message])
return <Prompt when={when} message={message} />
}
LeavePageBlocker.propTypes = {
when: PropTypes.bool.isRequired,
}
export default LeavePageBlocker
Run Code Online (Sandbox Code Playgroud)
您的页面:
const [dirty, setDirty] = setState(false)
...
return (
<>
<LeavePageBlocker when={dirty} />
...
</>
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
54323 次 |
最近记录: |