Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Router: How to render element on all routes, except one?

I have HTML structure like this:

<body>
  <nav>
     <!--navigation elements -->
  </nav>
  <div className='main'>
     <!--other elements -->
  </div>
  <div className='container'></div>
</body>

And routing defined like this:

<Router>
  <Fragment>
    <Navbar />
    <Route exact path="/" component={Landing} />
    <div className="container">
       <Alert />
       <Switch>
           <Route exact path="/register" component={Register} />
           <Route exact path="/login" component={Login} />
           <Route exact path="/profiles" component={Profiles} />
       </Switch>
    </div>
  </Fragment>
</Router>

The "container" element is present on all routes however I do not want it to be rendered on the "/" route.

How can I stop <div className="container"> from being rendered on the "/" route? I want it to be rendered on all other routes except of "/".

A solution I found, but don't want to use is to explicitly insert the element with class="container" in each component that is rendered in my <Switch>. Is there a better way?

like image 827
Sth Avatar asked Jun 21 '19 09:06

Sth


People also ask

How do I restrict routes in react router?

The Route component from react-router is public by default but we can build upon it to make it restricted. We can add a restricted prop with a default value of false and use the condition if the user is authenticated and the route is restricted, then we redirect the user back to the Dashboard component.

How can you prevent re rendering a total component if it hasn't changed?

1. Memoization using useMemo() and UseCallback() Hooks. Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.


3 Answers

You should be able to achieve what you require via nested routes and a "no match route".

The idea would be to introduce structure to your routing via nested routes, to restrict rendering of <div className="container"> to non / routes.

To do this, you could extract a component (ie WithContainer) that renders a <Route> for paths; /register, /login and /profiles, inside of the <div className="container">. You would then change your <Switch> to now render two routes for the following route cases;

  1. A <Route/> that renders the Landing component on an exact match of /
  2. A <Route/> that renders your new WithContainer component on no specific route (ie any path that does not exactly match /)

By using the <Switch> in this way, it causes the routing behaviour to render either Landing or WithContainer (but not both) depending on the first matched route. We take advantage of that behaviour to restrict rendering of the WithContainer (and in turn, the <div className="container"> element) for "non /" routes.

In code, this approach could be expressed as:

const WithContainer = () => (
    <div className="container">
       { /* Wrap routes in container div */ }
       <Route exact path="/register" component={Register} />
       <Route exact path="/login" component={Login} />
       <Route exact path="/profiles" component={Profiles} />
    </div>)

const Main = () => (
  <main> 
    <Switch>
      <Route exact path='/' component={Landing}/>
      <Route component={ WithContainer } /> {/* No match route */ }
    </Switch>
  </main>
)

Hope that helps!

like image 61
Dacre Denny Avatar answered Nov 13 '22 15:11

Dacre Denny


With the latest version of React Router, you can provide an array of strings for the path prop so that a specific route renders on multiple matches:

<Route path={['/one', '/two', '/three']} component={SomeComponent} />

Here's a link to the relevant documentation: https://reacttraining.com/react-router/web/api/Route/path-string-string.

like image 32
The Qodesmith Avatar answered Nov 13 '22 13:11

The Qodesmith


If you don't want to create a separate component, you can just do this. You need to keep the inner switch as well, if you want to keep the original functionality.

// parent switch
<Switch>
  <Route exact path="/" component={Landing} />
  // start route wrap!!!
  <Route> 
    <div className="container">
      <Switch>
        <Route exact path="/register" component={Register} />
        <Route exact path="/login" component={Login} />
        <Route exact path="/profiles" component={Profiles} />
      </Switch>
    </div>
  </Route>
 // end route wrap!!!
</Switch>

You should think of Routes as of any other UI components. You can nest them arbitrarily.

like image 2
Windom Earle Avatar answered Nov 13 '22 15:11

Windom Earle