-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k

Description
Router Switch Conditionals
What is
Sometimes we may wish to have a better way of controlling if a route is going to be rendered or not, without a redirect (as the wiki proposes). With this we can pass a conditional to a route as a prop so the switch may see if the route can render.
To this day work-around
While we don't have this resource, what I usually do, is pass a function to the path parameter of the route (inside a switch), an example as follows:
var user = null;
function isGuest(route) {
return user === null? route:"impossible route";
}
export default function App (props) {
return (
<Switch>
<Route path={isGuest("actual/route")} component={Component} />
</Switch>
);
}
What I'm doing is rendering an impossible route if the condition inside the function is not met, with this I can generate tons of functions to describe those conditions, such as: isGuest, isLogged, isAdmin
. Of course, that this method is not ideal.
Sample
How the router switch conditionals would work:
var user = null;
export default function App (props) {
return (
<Switch>
<Route path="actual/route" condition={user === null} component={Component} />
</Switch>
);
}
Returning true would allow the switch to consider this route when choosing which one to use.
Changes
The changes in the source code would be near to minimal
Switch class
class Switch extends React.Component {
render() {
return (
<RouterContext.Consumer>
{context => {
invariant(context, "You should not use <Switch> outside a <Router>");
const location = this.props.location || context.location;
let element, match;
// We use React.Children.forEach instead of React.Children.toArray().find()
// here because toArray adds keys to all child elements and we do not want
// to trigger an unmount/remount for two <Route>s that render the same
// component at different URLs.
React.Children.forEach(this.props.children, child => {
if (match == null && React.isValidElement(child)) {
element = child;
const path = child.props.path || child.props.from;
const cond = child.props.condition || true;
match = (path || cond)
? matchPath(location.pathname, { ...child.props, path })
: context.match;
}
});
return match
? React.cloneElement(element, { location, computedMatch: match })
: null;
}}
</RouterContext.Consumer>
);
}
}
The only thing that we are doing is adding a const that reads the condition and passing it for the match test altogether with the route comparison.