Coder
Coder

Reputation: 610

How <Switch> works when it encounters React Components in it?

Basically I am understanding someone else's code and modifying. In App.js it is checked if the user is logged in, he has to render the dashboard

App.js

        <Switch>
          <Redirect exact path="/" to="/dashboard"/>
          <Route path="/login" component={GuestBoard} /> 
          <EnsureSignedIn>
            <Switch>
              <Route path="/dashboard/" component={Dashboard}/>
              <Route path="/welcome/" component={Welcome}/>
           </Switch>
          </EnsureSignedIn>
       </Switch>

Basically <EnsureSignedIn> checks if the user has logged in, it renders all the children.

My question is: how <Switch> is rendering <EnsureSignedIn> which has no path. And also what exactly happens(what is the flow of rendering of components) if I keep writing React Components inside <Switch> ?

Say something like this

       <Switch>
          <Redirect exact path="/" to="/dashboard"/>
          <Route path="/login" component={GuestBoard} /> 
          <Component1 />
          <Component2 /> 
          <Component3 />
       </Switch>

EnsureSignedIn:

componentDidMount() {
    if (!this.props.user) {
      this.props.history.push('/login?next=' + this.props.currentURL);
    }
render() {
        return (this.props.user ? this.props.children : null);
      }

We have used redux, So user is props from the reducer.

Upvotes: 0

Views: 106

Answers (1)

caesay
caesay

Reputation: 17271

Switch is working as intended here even though the documentation recommended only having a Route or Redirect component as a direct child. It is however documented that Switch will render a single child - the first child which matches the current route. It also specifies that a <Route component without a path is allowed as a catch-all, that is what is happening here.

To simplify, Switch will iterate over all of its children, one by one, from top down, and select the first component where the path matches the current route or the component has no path specified (catch-all component). You can see this working here: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Switch.js#L47 note that it's looking for the props of a Route component but there is no code specifically requiring the component to be a Route.

In your case, unauthenticated pages will render just fine, because they appear before the EnsureSignIn child component. However, if no other routes match, EnsureSignIn will be rendered and, presumably, this component will redirect back to the login page if the user is not signed in - preventing them from accessing the protected pages beneath.

If you were to restructure your code like this:

 <Switch>
      <span>Hello!!</span>
      <Redirect exact path="/" to="/dashboard"/>
      <Route path="/login" component={GuestBoard} /> 
      <EnsureSignedIn>
        <Switch>
          <Route path="/dashboard/" component={Dashboard}/>
          <Route path="/welcome/" component={Welcome}/>
       </Switch>
      </EnsureSignedIn>
   </Switch>

That would also be completely valid, but the only thing that would ever be rendered is "Hello!!" because that's the first matching component.

Upvotes: 2

Related Questions