Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-router: prevent navigation to target route

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} component={AppContainer}>
    <Route path="view-1"
        onEnter={ view1onEnter }
        onLeave={ view1onLeave }
        component={ View1 }
        canNavigate={ false }
    />
    <Route path="view-2"
        onEnter={ view2onEnter }
        onLeave={ view2onLeave }
        component={ 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?

like image 258
Kiril Avatar asked Apr 09 '16 09:04

Kiril


1 Answers

React 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.

like image 133
Dennis Nerush Avatar answered Sep 29 '22 02:09

Dennis Nerush