javascriptreactjsreact-hooksreact-router-domreact-routing

Nested routing in react.js is not giving the desired results


I want to display a custom component Resource.js whenever I click the linked text within a labCard.js component. On using the Outlet hook the Resource component is displayed within the lab Card and the Body.js component is not replaced. Body.js component is a collection of labCards component. My desire is to display the resource component in place of body component whenever I click Begin on the labCard component.

This is the App component

import React from 'react'
import { Routes, Route } from 'react-router-dom'
import Navbar from './components/Navbar'
import Home from './components/Home'
import Body from './components/Body'
import AboutUs from './components/AboutUs'
import GetHelp from './components/GetHelp'
import Footer from './components/Footer'
import Resource from './subComponents/Resource'
import './App.css';

function App() {
  return (
    <div>
      <Navbar />
      <Routes>
        <Route path="/" element={ <Home /> } />
        <Route path="/body/*" element={ <Body /> } >
          <Route path="resource" element={ <Resource /> } />
        </Route>
        <Route path="/about" element={ <AboutUs /> } />
        <Route path="/help" element={ <GetHelp /> } />
      </Routes>
      <Footer />
    </div>
  );
}

export default App;

This is the body Component

import React from 'react'
import LabCard from '../subComponents/LabCard'
import { data } from '../data'
import './Body.css'

export default function Body() {
    const [labData, setLabData] = React.useState(data)
    let labCardElements = labData.map(lab => 
    <LabCard 
        key={lab.id} 
        labID={lab.id} 
        labType={lab.type}
        labTitle={lab.title} 
        labResourceUrl={lab.resourceUrl}
    />)
    return (
        <section className='experiment-body-section'>
            <h1 className='experiment-body--title'>Experiments</h1>
            <p className='experiment-body--description'>Here are all the experiments</p>
            <div className='experiment-body'>
                {labCardElements}
            </div>
        </section>
    )
}

This is the labCard component

import React from 'react'
import { Link } from 'react-router-dom'
import './Card.css'

export default function LabCard(props) {
    return (
        <div className='lab-card'>
            <p className='lab-card--id'>{props.labType}</p>
            <h2 className='lab-card--title'>{props.labTitle}</h2>
            <div className="parent">
                <div className='lab-card--overlay'></div>
                <Link to="resource" className='lab-card-overlay--button'>Begin</Link>
            </div>
        </div>
    )
}

Solution

  • If I'm understanding your question/issue correctly, it is that you don't want to render both the Body and Resource components at the same time.

    In this case you should render Body on a nested index route. Both nested routes will be rendered into an Outlet by default on the parent route.

    <Route path="/body">
      <Route index element={<Body />} />               // <-- "/body"
      <Route path="resource" element={<Resource />} /> // <-- "/body/resource"
    </Route>