Search code examples
javascriptreactjsreact-router-dom

React JS: Single Page Application has missing pages when using react-router-dom


I have my SPA with multiple pages and I want to be able to scroll from the first page to the last continuously, but with react-router-dom when I click a link it shows only one page, eliminating the others - the routing works perfectly but the other pages disappear except for the one with the active link. Am I missing something? I've read some tutorials about SPA and everything seems to be fine. I'm using react-router-dom v.6.9. This is my code:

Navigation:

<Nav className="justify-content-evenly align-items-center flex-grow-1 nav-tab">
  <Link exact to="/">Home</Link>
  <Link exact to="/aboutus">About Us</Link>
  <Link exact to="/services">Services</Link>
  <Link exact to="/offers">Packages</Link>
  <Link exact to="/contact">Contact Us</Link>
</Nav>

And this is inside App.js:

<Router>
  <Navigation />
  <Routes>
    <Route index element={<Home />} />
    <Route path="/aboutus" element={<AboutUs />} />
    <Route path="/offers" element={<Offers />} />
    <Route path="/services" element={<Services />} />
    <Route path="/contact" element={<ContactUs />} />
  </Routes>
  <Footer />
</Router>

Solution

  • This is the designed and expected behavior when using react-router, you are simulating a multi-page application even though the entire React app is effectively still a SPA. In other words, RRD manipulates the URL in the address bar client-side and exclusively renders routed content.

    If you want all your content to still be a "single page app" then don't use react-router, render all the content into a single node element and use raw anchor tags to link to specific sections, i.e. by id hash.

    <Nav className="justify-content-evenly align-items-center flex-grow-1 nav-tab">
      <a to="/#home">Home</a>
      <a to="/#aboutus">About Us</a>
      <a to="/#services">Services</a>
      <a to="/#offers">Packages</a>
      <a to="/#contact">Contact Us</a>
    </Nav>
    
    <Navigation />
    <Home />
    <AboutUs />
    ....
    <ContactUs />
    

    Where each content component is assigned an id attribute you are wanting to link to.

    const Home = () => (
      <div id="home">
        ....
      </div>
    );
    

    If the intent is to still render some content on specific "pages" as a "multi-page" app and you still want to navigate and scroll to specific pages and sections then you can use something like react-router-hash-link which has basic compatibility with react-router@6.

    For example, if the "services", "offers", and "contact us" sections were all on the about page, you could do something similar to the following:

    import { Link } from 'react-router-dom';
    import { HashLink } from 'react-router-hash-link';
    
    ...
    
    <Nav className="justify-content-evenly align-items-center flex-grow-1 nav-tab">
      <Link to="/">Home</Link>
      <Link to="/aboutus">About Us</Link>
      <HashLink to="/aboutus#services">Services</HashLink>
      <HashLink to="/aboutus#offers">Packages</HashLink>
      <HashLink to="/aboutus#contact">Contact Us</HashLink>
    </Nav>
    
    <Router>
      <Navigation />
      <Routes>
        <Route index element={<Home />} />
        <Route path="/aboutus" element={<AboutUs />} />
      </Routes>
      <Footer />
    </Router>
    
    const AboutUs = () => {
      ....
    
      return (
        ...
    
        <Offers />
        <Services />
        <ContactUs />
      );
    };
    

    Either of these approaches should provide a good general direction to work with.