Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using React-Router with a layout page or multiple components per page

I am adding react router to an existing project.

At present a model is passed in to a root component which contains a navigation component for the sub navigation and a main component.

The examples of react router I've found only have one child component, what is the best way to have multiple child components change without repeating the layout code in both?

like image 576
Tom Avatar asked Oct 11 '15 08:10

Tom


People also ask

Is react good for multiple pages?

The use cases for having multiple pages in a single React app are pretty simple. You can create a website, and easily classify different types of content on different pages. But, it should also be understood that the default implementation of React is made to use a single HTML file, and this is by design.

How do you create a simple react router to navigate multiple pages?

To use react-router, you do the following: Create a file with routes defined using Route, IndexRoute components. Inject the Router (with 'r'!) component as the top-level component for your app, passing the routes defined in the routes file and a type of history (hashHistory, browserHistory)

How many pages are involved in react routing?

In this example we have 3 “pages” handled by the router: a home page, an about page, and a users page.

Is react router single-page application?

Everything essential you need to know about React Router. React thrives on being one of the premier tools to build single-page applications, which used to be a fairly foreign concept when I started building my first React app.


2 Answers

If I understood you correctly, to achieve that you would define multiple components in your Route. You can use it like:

// think of it outside the context of the router, if you had pluggable // portions of your `render`, you might do it like this <App children={{main: <Users/>, sidebar: <UsersSidebar/>}}/>  // So with the router it looks like this: const routes = (   <Route component={App}>     <Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}}/>     <Route path="users" components={{main: Users, sidebar: UsersSidebar}}>       <Route path="users/:userId" component={Profile}/>     </Route>   </Route> )  class App extends React.Component {   render () {     const { main, sidebar } = this.props;     return (       <div>         <div className="Main">           {main}         </div>         <div className="Sidebar">           {sidebar}         </div>       </div>     )   } }  class Users extends React.Component {   render () {     return (       <div>         {/* if at "/users/123" `children` will be <Profile> */}         {/* UsersSidebar will also get <Profile> as this.props.children,             so its a little weird, but you can decide which one wants             to continue with the nesting */}         {this.props.children}       </div>     )   } } 

Also check out the sidebar example app, should help you more.

Edit: As per @Luiz's comment:

In the latest version of router (v3) the components are in the root of the props object

So:

const { main, sidebar } = this.props.children; 

becomes:

const { main, sidebar } = this.props; 

EDIT: In the react-router v4 this can be accomplished like (as per the example provided in the new docs):

import React from 'react' import {   BrowserRouter as Router,   Route,   Link } from 'react-router-dom'  // Each logical "route" has two components, one for // the sidebar and one for the main area. We want to // render both of them in different places when the // path matches the current URL. const routes = [   { path: '/',     exact: true,     sidebar: () => <div>home!</div>,     main: () => <h2>Home</h2>   },   { path: '/bubblegum',     sidebar: () => <div>bubblegum!</div>,     main: () => <h2>Bubblegum</h2>   },   { path: '/shoelaces',     sidebar: () => <div>shoelaces!</div>,     main: () => <h2>Shoelaces</h2>   } ]  const SidebarExample = () => (   <Router>     <div style={{ display: 'flex' }}>       <div style={{         padding: '10px',         width: '40%',         background: '#f0f0f0'       }}>         <ul style={{ listStyleType: 'none', padding: 0 }}>           <li><Link to="/">Home</Link></li>           <li><Link to="/bubblegum">Bubblegum</Link></li>           <li><Link to="/shoelaces">Shoelaces</Link></li>         </ul>          {routes.map((route, index) => (           // You can render a <Route> in as many places           // as you want in your app. It will render along           // with any other <Route>s that also match the URL.           // So, a sidebar or breadcrumbs or anything else           // that requires you to render multiple things           // in multiple places at the same URL is nothing           // more than multiple <Route>s.           <Route             key={index}             path={route.path}             exact={route.exact}             component={route.sidebar}           />         ))}       </div>        <div style={{ flex: 1, padding: '10px' }}>         {routes.map((route, index) => (           // Render more <Route>s with the same paths as           // above, but different components this time.           <Route             key={index}             path={route.path}             exact={route.exact}             component={route.main}           />         ))}       </div>     </div>   </Router> )  export default SidebarExample 

Make sure you check out the new React Router v4 docs here: https://reacttraining.com/react-router/

like image 199
knowbody Avatar answered Oct 19 '22 07:10

knowbody


2019 +

The simple and clean way to do it and avoid abusive re-rendering is (tested on react router v5, need to be confirmed on react router v4):

       <Switch>          <Route exact path={["/route1/:id/:token", "/"]}>           <Layout1>             <Route path="/route1/:id/:token" component={SetPassword} />             <Route exact path="/" component={SignIn} />           </Layout1>         </Route>         <Route path={["/route2"]}>           <Layout2>             <Route path="/route2" component={Home} />           </Layout2>         </Route>       </Switch> 

which can be refactored to:

const routes = [   {     layout:Layout1,     subRoutes:[       {         path:"/route1/:id/:token",         component:SetPassword       },       {         exact:true,         path:"/",         component:SignIn       },     ]   },   {     layout:Layout2,     subRoutes:[       {         path:"/route2",         component:Home       },     ]   } ]; 

with:

      <Switch>         {routes.map((route,i)=>           <Route key={i} exact={route.subRoutes.some(r=>r.exact)} path={route.subRoutes.map(r=>r.path)}>             <route.layout>               {route.subRoutes.map((subRoute,i)=>                 <Route key={i} {...subRoute} />               )}             </route.layout>           </Route>         )}       </Switch> 
like image 36
Sebastien Horin Avatar answered Oct 19 '22 05:10

Sebastien Horin