1

I am building a consumer facing app with a admin dashboard. I want to keep the routing separate for them and so trying to delegate :-

App.js

import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

//styles
import './style/bootstrap/bootstrap.scss';

//apps
import Mainapp from './mainapp/Mainapp';
import Admin from './admin/Admin';

const MainappContainer = () => (
  <Mainapp />
);

const AdminContainer = () => (
  <Admin />
);

class App extends Component{
  render(){
    return (
      <Router>
        <Switch>
            <Route path="/admin" component={AdminContainer}/>
            <Route path="/" component={MainappContainer}/>
        </Switch>
      </Router>
    )
  }
}

export default App;

Admin.js

import React, {Component} from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';


//styles
import './admin-style.scss';

//layout
import ControlPanel from './component/layout/ControlPanel';
import Navbar from './component/layout/Navbar';

//pages
import Quote from './component/pages/quote/Quote';

class Admin extends Component{
    render(){
      return (
        <div className="adminWrapper">
          <ControlPanel />
          <section className="viewPanel">
            <Navbar />
            <Router>
              <Route path="/quote" component={Quote}/>
            </Router>
          </section>
        </div>
      )
    }
  }

  export default Admin;

However when I hit the URL

http://localhost:3000/admin/quote

it doesn't seem to load the quote component

Quote.js

import React, { Component } from 'react';

class Quote extends Component {
    render() {
        return (
            <div className="float-right pr-3">
                <h3>
                    Quote Page
                </h3>
            </div>
        )
    }
}

export default Quote;
8
  • The path for the quote page isn't /admin/quote if you're already in /admin. Commented Sep 5, 2019 at 12:02
  • tried "/quote", still gives a blank page Commented Sep 5, 2019 at 12:04
  • 2
    The other problem is that your parent there is exact, so only matches the root /admin Commented Sep 5, 2019 at 12:05
  • Remove exact from this <Route exact path="/admin" component={AdminContainer}/> Commented Sep 5, 2019 at 12:39
  • And change <Route exact path="/admin/quote" component={Quote}/> to <Route exact path="/quote" component={Quote}/> Commented Sep 5, 2019 at 12:40

3 Answers 3

3

When dealing with nested subroutes, the easiest solution is to use match.

path - (string) The path pattern used to match. Useful for building nested Routes.

url - (string) The matched portion of the URL. Useful for building nested Links.

By design, components placed inside a Route's component render method are given several additional props from react-router-dom. Among them are history and match. You can leverage these props to either to match against sub routes and/or to control browser history location.

In addition, you only need one instance of BrowserRouter sitting at the top-level of the application, then you can use Switch to optionally render any main or sub routes. And you don't need to use class components unless you're utilizing state and/or a class field.

A very basic, rudimentary working example of your application:

Edit React-Router-Dom Nested Routing


src/components/Admin/index.js

import React from "react";
import { Switch, Link, Route } from "react-router-dom";
import ControlPanel from "../ControlPanel";
import Quote from "../Quote";

// since Admin is placed inside a Route's component render
// method, it has access to history and match
function Admin({ history, match }) {
  return (
    <div className="adminWrapper">
      <ControlPanel />
      <section className="viewPanel">
        <Link to={`${match.url}/quote`}>View quote</Link>
        <br />
        <Switch>
          <Route exact path={`${match.path}/quote`} component={Quote} />
        </Switch>
      </section>
      <br />
      <button type="button" onClick={() => history.goBack()}>
        Go Back
      </button>
    </div>
  );
}

export default Admin;

index.js

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
import Admin from "./components/Admin";

const linkStyle = {
  padding: "0 10px"
};

function App() {
  return (
    <BrowserRouter>
      <Link style={linkStyle} to="/">
        Home
      </Link>
      <Link style={linkStyle} to="/admin">
        Admin
      </Link>
      <Switch>
        <Route path="/admin" component={Admin} />
        <Route path="/" render={() => <h1>Main App</h1>} />
      </Switch>
    </BrowserRouter>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
Sign up to request clarification or add additional context in comments.

6 Comments

i think this is where he is doing wrong. ReactDOM.render(<App />, document.getElementById("root")); i thing you won the bounty. congrats
How can i use match on a class component? Where this function has history and match as arguments - I can't find a place to incorporate match in a class component to be able to try to follow this example
@Mel - Before moving forward, I'd highly recommend stepping back and investing in some learning and education. I think you're trying to do too much and too fast. Please consider investing in this online, at your own pace, course: udemy.com/course/react-2nd-edition. As of writing, it's only $10 and it covers a lot of fundamentals, its as slow or as fast past as you need, and it comes with in-depth explanations. I enrolled and completed it when I was first learning, and I found it to be an invaluable tool.
That said, to answer your question... class based components have this.props. If a class component is passed into a Route's component property, it'll be merged with Route props: this.props.history, this.props.match, and this.props.location.
I've done both udemy react classes. I find the explanations skim over what is actually happening, but I'll do it again in case I am better able to substantively understand what the steps are explaining. The thing is, I tried this.props.match - and got redirected to localhost/account immediately (instead of on a refresh). That is not what I'm looking to achieve. Ill redo the udemy and try to find a way to get this to render inside the dash. Thank you very much for trying to help.
|
1
+50

Follow the Nested Routing Example

The main changes you need to do are:
1. Remove the <Router></Router> from Admin component and
2. Prepend match.path to "/quotes", like it is done in Topics component in the example. In the example, Topics is a function component so it is receiving match as function parameter. As your Admin component is class component, you can access it as this.props.match in render method.

<Route path={`${this.props.match.path}/quote`} component={Quote}/>

3 Comments

Yes I did this but I keep getting this error - 'Cannot read property 'path' of undefined'. I am using ES6.
That's because your component for /admin path is AdminContainer, which is not passing the down the received props to Admin. Change it to const AdminContainer = (props) => ( <Admin {...props} /> );
I tried this - but i keep getting redirected to a page which is the equivalent of localhost/quote. where i want to display my version of quote inside a div tag on another page
0
 <Route exact path="/admin" component={AdminContainer}/>     
 <Route exact path="/admin/quote" component={Quote}/>

This won't route you to /admin/quote instead it will route you to /admin/admin/quote.

Since it is inside admin just /quote is enough

<Route path="/admin" component={AdminContainer}/>
<Route path="/quote" component={Quote}/>

2 Comments

try copy pasting once
removing exact makes the page remain on dashboard, however the quote route is still not loading

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.