React Router v4 nested routes help

Greetings to all!

I am having issues with React Router version 4.

The Routing is correct and the NavLink / Link in the header is also correct but the issue I have is whenever I click on a link it takes me to that component / page without rendering Header and Footer, what do you think the issue is?

I searched around and found “You should use {this.props.children}” and I did but nothing is working.

index.js:

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

//Pages
import Home from './Home';
import About from './main_pages/About';
import Faq from './main_pages/Faq';
import Login from './main_pages/Login';
import Register from './main_pages/Register';


ReactDOM.render((
    <BrowserRouter>
        <Switch>
         <Route exact path="/" component={Home}/>
         <Route path='/about' component={About}/>
         <Route path='/faq' component={Faq}/>
         <Route path="/login" component={Login}/>
         <Route path="/register" component={Register}/>
        </Switch>
   </BrowserRouter>),
  document.getElementById('root')
);

Header.js:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Navbar, Nav } from 'react-bootstrap';
import { FaHome, FaExclamation, FaQuestion, FaSignIn, FaUser } from 'react-icons/lib/fa';
import { NavLink } from 'react-router-dom';
import $ from 'jquery';

class Header extends Component {

    componentDidMount() {
        $(window).on("scroll", function() {
            if($(window).scrollTop() > 20) {
                $(".nav-header").addClass("active");
            } else {
                //remove the background property so it comes transparent again (defined in your css)
               $(".nav-header").removeClass("active");
            }
        });
    }

    render() {
        return (
                <Navbar collapseOnSelect className="nav-header navbar-fixed-top">
                    <div className="container">
                        <Navbar.Header>
                                <img src={require('../../../imgs/logo.png')} alt="logo" width="80"/>
                                <Navbar.Toggle />
                        </Navbar.Header>
                        <Navbar.Collapse>
                            {/* -- Left nav -- */}
                            <Nav className="nav navbar-nav">
                                <NavLink to="/"><span><FaHome /></span> Home </NavLink>
                                <NavLink to="/about"><span><FaExclamation /></span> About </NavLink>
                                <NavLink to="faq"><span><FaQuestion /></span> FAQs </NavLink>
                            </Nav>

                            {/* -- Right nav -- */}
                            <Nav pullRight className="nav navbar-nav">
                                <NavLink to="/login"><span><FaSignIn /></span> Login </NavLink>
                                <NavLink to="/register"><span><FaUser /></span> Register </NavLink>
                            </Nav>
                        </Navbar.Collapse>
                    </div>
                </Navbar>          
        )
    }
}
export default Header;

Home.js:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'semantic-ui-react';

//CSS
require('../css/style.css');

//Home components
import Latest_orders from './home_components/Latest_orders';
import What_we_do from './home_components/What_we_do';
import MapContainer from './home_components/Map';

//Header && Footer
import Header from './header_footer/Header';
import Footer from './header_footer/Footer';

class Home extends Component {
    render() {
        return (
            <div>
                {/* -- ( Header ) -- */}
                <Header />
                {this.props.children}
                {/* -- ( Main content ) -- */}
                <div className="jumbotron"> 
                    <div className="container text-center">
                        <span className="jumbo-center">
                            <h1> Warsha Plus </h1>
                            <h2> We are the best </h2>
                            <Button color='orange' style={{ padding: '17px', fontSize: '17px' }}>Order Now</Button>
                        </span>
                    </div>
                </div>

                {/* -- ( Latest Orders ) -- */}
                <Latest_orders />

                {/* -- ( what we do ) -- */}
                <What_we_do />

                {/* -- ( Google Map API ) -- */}
                <MapContainer />

                {/* -- ( Footer ) -- */}
                <Footer />
            </div>
        );
    }
}
export default Home;

Screen shot of the website:

Hi @Sora

Nothing stands out as being obviously wrong with your code… as far as I can tell I’d have thought it should work. If you could put together a bare-bones runnable example that demonstrates the problem I’d be happy to take a more in-depth look.

2 Likes

The only thing I can do is give you a git clone link…
is it ok?

Yeah sure, that’d be fine

Thank you

here it is: https://warshaplus@bitbucket.org/warshaplus/website-new-backend.git

make sure you do composer install and npm install!

Thanks for the link. I’ve had a look at the code and I see what you mean now.

One way to achieve what you want is to create a layout component that you can use to wrap all the routes that need to share the header and footer, something like this:

<BrowserRouter>
  <Switch>
    <Layout>
      <Route exact path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/faq" component={Faq} />
      <Route path="/login" component={Login} />
      <Route path="/register" component={Register} />
    </Layout>
    {/* dashboard routes */}
  </Switch>
</BrowserRouter>

The component itself would look something like this:

class Layout extends Component {
  render() {
    return (
      <div>
        <Header />
        {this.props.children}
        <Footer />
      </div>
    );
  }
}

The line {this.props.children} will just render out any visible child components, which in this case would be one of the five route components.

Edit: as the Layout component doesn’t rely on any lifecycle methods or component state, it could be written as a simpler functional component instead, eg:

const Layout = ({ children }) => (
  <div>
    <Header />
    {children}
    <Footer />
  </div>
);
2 Likes

Hello, I apologize for the late reply.

Your code is understandable and I like the way you explained it.

Many thanks to you friend!

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.