var Settings = React.createClass({
statics: {
willTransitionTo: function (transition, params, query, callback) {
auth.isLoggedIn((isLoggedIn) => {
transition.abort();
callback();
});
},
willTransitionFrom: function (transition, component) {
if (component.formHasUnsavedData()) {
if (!confirm('You have unsaved information,'+
'are you sure you want to leave this page?')) {
transition.abort();
}
}
}
}
//...
});
import { Lifecycle } from 'react-router'
const Home = React.createClass({
// Assuming Home is a route component, it may use the
// Lifecycle mixin to get a routerWillLeave method.
mixins: [ Lifecycle ],
routerWillLeave(nextLocation) {
if (!this.state.isSaved)
return 'Your work is not saved! Are you sure you want to leave?'
},
// ...
})
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?'
},
// ...
})
)
import createBrowserHistory from 'history/createBrowserHistory'
export const history = createBrowserHistory()
...
import { history } from 'path/to/history';
<Router history={history}>
<App/>
</Router>
然后在你的组件中你可以使用 history.block
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
}
}
import { useEffect, useState } from "react";
import { usePrevious } from "./usePrevious";
const useConfirmation = ({ router, route, items }) => {
const [needConfirmation, setNeedConfirmation] = useState(false);
// You can use for the prevState any value, in my case it was length of items
const prevItemsLength = usePrevious({ length: items?.length });
const commonMsg =
"you-have-unsaved-information-are-you-sure-you-want-to-leave-this-page";
const onBeforeUnload = (e) => {
if (needConfirmation) {
e.returnValue = true;
return commonMsg;
}
return null;
};
const routerWillLeave = () => {
if (needConfirmation) {
return commonMsg;
}
return true;
};
useEffect(() => {
if (prevItemsLength?.length > items?.length) {
setNeedConfirmation(() => true);
}
}, [items]);
useEffect(() => {
if (needConfirmation) {
window.addEventListener("beforeunload", onBeforeUnload);
router.setRouteLeaveHook(route, routerWillLeave);
} else {
router.setRouteLeaveHook(route, () => {});
window.removeEventListener("beforeunload", onBeforeUnload);
}
return () => window.removeEventListener("beforeunload", onBeforeUnload);
}, [needConfirmation]);
return [needConfirmation, setNeedConfirmation];
};
export { useConfirmation };
然后,在另一个文件中,我们在保存数据后禁用确认功能:
const [needConfirm, setNeedConfirm] = useConfirmation({
router,
route,
items,
});
const saveChanges = useCallback(() => {
//before turning off confirmation, there may be a request to the API to save our data
//if request was success then we set the 'needConfirm' value to 'false'
setNeedConfirm(() => false);
});