I'm relatively new to React and I'm wondering what's the standard here.
Imagine I have a react-router like this one:
<Router history={history}> <Route path="/" component={App}> <Route path="home component={Home} /> <Route path="about" component={About} /> <Route path="inbox" component={Inbox} /> <Route path="contacts" component={Contacts} /> </Route> </Router> And now I want to remove two routes if prop.mail is set to false, so a sane way of doing that would look like this:
<Router history={history}> <Route path="/" component={App}> <Route path="home component={Home} /> <Route path="about" component={About} /> { if.this.props.mail ? <Route path="inbox" component={Inbox} /> <Route path="contacts" component={Contacts} /> : null } </Route> </Router> But there are 2 routes and React returns error:
expressions must have one parent element.
I don't want to use multiple ifs here. What's the preferred React way of handling this?
08 Answers
Put them in an array (assign the keys also):
{ if.this.props.mail ? [ <Route key={0} path="inbox" component={Inbox} />, <Route key={1} path="contacts" component={Contacts} /> ] : null } With latest React version, you can try React.Fragment also, like this:
{ if.this.props.mail ? <React.Fragment> <Route path="inbox" component={Inbox} />, <Route path="contacts" component={Contacts} /> </React.Fragment> : null } 7You can leverage short hand fragments to return a list of children along with Logical '&&' Operator for conditional rendering. Nice and clean! 😄
{this.props.mail && <> <Route path="inbox" component={Inbox} />, <Route path="contacts" component={Contacts} /> </> } You must been use a fragment tag e.g(div, <>,...).
Check this short solution:
{ if.this.props.mail ? <> <Route path="inbox" component={Inbox} /> <Route path="contacts" component={Contacts} /> </> : null } 1just try enclosing the code after the return statement in an element like <div>....code </div>,etc.
eg:-
const Div =()=>{ return <div> <Button name="Save" ></Button> <Button name="Edit"></Button> <Button name="Cancel"></Button> </div>} 02020 update
I have checked out every solution from answers. Here is the breakdown for regular React:
1. React Fragment
When i wanted to use it once, without adding additional DOM node - it worked. When i tried to use second React.Fragment got really bad errors. Wasn't able to fix it.
2. View
I was unable to import View properly. I don't know if this is only for Reactjs, or Native, but this does not work
3. Div
What actually worked was to put HTML into Div
Faced the same error in a similar situation (React Native).
export default class App extends React.Component { render() { return ( <StatusBar barStyle="default" /> <AppContainer /> ); } } As indicated in the error prompt the JSX expression requires to have one parent element, hence wrap the elements in the return expression with a parent element. The flex: 1 style was added to allow the <View> element assume the height of the entire screen.
export default class App extends React.Component { render() { return ( <View style={{flex: 1}}> <StatusBar barStyle="default" /> <AppContainer /> </View> ); } } 2This one works for me.
<React.Fragment> …….. </React.Fragment>
If you're using <Switch>, then using <div> and <React.Fragment> to wrap your routes will break it.
I like the idea of a <ProtectedRoute> component:
import { Component } from 'react'; import { Redirect, Route } from 'react-router-dom'; class ProtectedRoute extends Component<any> { render() { const { component: Component, allow, ...props } = this.props; if (!allow) { return <Redirect to={{ pathname: '/signin' }} />; } return <Route {...props} render={(props) => <Component {...props} />} />; } } export default ProtectedRoute; Then use it like below:
<Router history={history}> <Route path="/" component={App}> <Route path="home" component={Home} /> <Route path="about" component={About} /> <ProtectedRoute path="inbox" component={Inbox} allow={this.props.mail} /> <ProtectedRoute path="contacts" component={Contacts} allow={this.props.mail} /> </Route> </Router>