I'm using react-router with history useQueries(createHashHistory)()
and I have several routes that I want to prevent navigation to based on route's configuration.
So routes config is like:
<Route path="/" name={RouteNames.APP} ponent={AppContainer}>
<Route path="view-1"
onEnter={ view1onEnter }
onLeave={ view1onLeave }
ponent={ View1 }
canNavigate={ false }
/>
<Route path="view-2"
onEnter={ view2onEnter }
onLeave={ view2onLeave }
ponent={ View2 }
canNavigate={ true }
/>
...
</Route>
So let's assume I'm on #/view-2
and call an action like history.push({pathname: '/view-1'});
. But as soon as route view-1
has a flag canNavigate={false}
- I want to prevent navigation to it and show a message without changing a hash and any other side effects (like calling onLeave
hook of view-2
).
I was thinking about listening to history
:
history.listenBefore((location, callback) => {
//e.g. callback(false) to prevent navigation
})
but I can't get the route instance to check canNavigate
flag.
Later I've found out that history
has a method match
which actually gets next router state based on the given location
:
history.listenBefore((location, callback) => {
history.match(location, (error, redirectLocation, nextState) => {
const route = _.last(nextState.routes);
if (route.canNavigate) {
callback();
} else {
callback(false);
}
});
})
but the problem is that history.match
calls onLeave
hook for view-2
inside (which may, for example, clear state even though the user stays on the view-2
view).
The question: is it possible to prevent navigation from view-2
without any changes at all in history/router and making this decision based on target route configuration?
I'm using react-router with history useQueries(createHashHistory)()
and I have several routes that I want to prevent navigation to based on route's configuration.
So routes config is like:
<Route path="/" name={RouteNames.APP} ponent={AppContainer}>
<Route path="view-1"
onEnter={ view1onEnter }
onLeave={ view1onLeave }
ponent={ View1 }
canNavigate={ false }
/>
<Route path="view-2"
onEnter={ view2onEnter }
onLeave={ view2onLeave }
ponent={ View2 }
canNavigate={ true }
/>
...
</Route>
So let's assume I'm on #/view-2
and call an action like history.push({pathname: '/view-1'});
. But as soon as route view-1
has a flag canNavigate={false}
- I want to prevent navigation to it and show a message without changing a hash and any other side effects (like calling onLeave
hook of view-2
).
I was thinking about listening to history
:
history.listenBefore((location, callback) => {
//e.g. callback(false) to prevent navigation
})
but I can't get the route instance to check canNavigate
flag.
Later I've found out that history
has a method match
which actually gets next router state based on the given location
:
history.listenBefore((location, callback) => {
history.match(location, (error, redirectLocation, nextState) => {
const route = _.last(nextState.routes);
if (route.canNavigate) {
callback();
} else {
callback(false);
}
});
})
but the problem is that history.match
calls onLeave
hook for view-2
inside (which may, for example, clear state even though the user stays on the view-2
view).
The question: is it possible to prevent navigation from view-2
without any changes at all in history/router and making this decision based on target route configuration?
1 Answer
Reset to default 2React cannot prevent the navigation once you've called history.push.
You should encapsulate the history service with a custom one that will check whether it is possible to navigate and if it is then call history.push. otherwise prevent the navigation and keep the state.