'My react onClick navigate shows URL, but does not render component

I am new to React router here and I am trying to make clicking on a recipe in my 'BrowseRecipes' page redirect to a page dedicated to that recipe. However, when I click on the recipe, the URL shows the correct URL /browse/${recipeID}, but the page I assign to this route does not render. Only the /browse page with a list of all the recipes renders. Does anyone know why?

Here is my APP.js

import AddNewRecipe from './components/AddNewRecipe'
import BrowseRecipes from './components/BrowseRecipes'
import { currentState } from './components/redux';
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Switch, Route, Routes, Link, useParams} from "react-router-dom";
import AuthReqPage from "./components/AuthReqPage"
import Navbar from "./components/Navbar"
import RecipePage from "./components/BrowseRecipes/RecipePage"
import PageNotFound from "./components/PageNotFound"

function App(props) {
  
  return (
    <Router>
        <div className="App">
          <Navbar />
            
          <Routes>
            <Route path='/add' element={<AddNewRecipe />} />
            <Route path='/' element={<BrowseRecipes />} />
            <Route path='/browse' element={<BrowseRecipes />}>
              <Route path=':recipeID' element={<RecipePage />}/>
            </Route>
            <Route path='/authrequired' element={<AuthReqPage />} />
            <Route path='/*' element={<PageNotFound />} />
          </Routes>
        </div>
    </Router>
  );
}

export default App;

Here is my BrowseRecipe component/page:

export function BrowseRecipes (props){
    console.log('browseRecipe running')
    
    let navigate = useNavigate()
    let params=useParams()
    console.log(params.recipeID)
    
    if(props.recipeStore.length>0)
    {
        var displayRecipes = props.recipeStore.map(
            elem=> 
            {   
                return (<li key={elem.recipeID} className='recipeDisplayBox' onClick={()=>navigate(`/browse/${elem.recipeID}`)}>
                {elem.title}, 
                Prep: {elem.prepTime.numeral} {elem.prepTime.unit}
                </li>)
            }

        )
    }
    return(
        <div>
        <h1>Browse Recipes</h1>
        <h2>Your recipes:</h2>
        <ul>
            {displayRecipes}
        </ul>
        </div>
    )
}

const mapStateToProps=(state)=>{
    return {recipeStore: state.recipe}}

export default connect(mapStateToProps)(RequireAuth(BrowseRecipes))

And here is the individual recipe page that failed to render:

   export function RecipePage (props){
    console.log('RecipePage running')
    
    let params=useParams()
   
    return(
        <div>
        <h1>{params.recipeID}</h1>
       
        
        </div>

    )
}

const mapStateToProps=(state)=>{
    return {recipeStore: state.recipe}}

export default connect(mapStateToProps)(RequireAuth(RecipePage))

"RequireAuth" here is a higher-order component that redirects the page to 'Please Sign In' page if the user is not signed in.

Did I misunderstand something about the use of UseParams? Please help me shed some light! Thank you very much



Solution 1:[1]

You've rendered the RecipePage component on a nested route from the "/browse" route rendering the BrowseRecipes component.

<Route path='/browse' element={<BrowseRecipes />}>
  <Route path=':recipeID' element={<RecipePage />}/>
</Route>

In this configuration the BrowseRecipes is required to render an Outlet component for the nested routes to be rendered into.

Example:

import { Outlet, useNavigate, useParams } from 'react-router-dom';

export function BrowseRecipes (props) {
  const navigate = useNavigate();
  const params = useParams();
  
  let displayRecipes;
  if (props.recipeStore.length) {
    displayRecipes = props.recipeStore.map(elem => {   
      return (
        <li
          key={elem.recipeID}
          className='recipeDisplayBox'
          onClick={() => navigate(`/browse/${elem.recipeID}`)}
        >
          {elem.title}, 
          Prep: {elem.prepTime.numeral} {elem.prepTime.unit}
        </li>
      );
    });
  }

  return (
    <div>
      <h1>Browse Recipes</h1>
      <h2>Your recipes:</h2>
      <ul>
        {displayRecipes}
      </ul>
      <Outlet /> // <-- nested routes render here
    </div>
  );
}

If you don't want to render both BrowseRecipes and RecipePage at the same time, then create a nested index route specifically for BrowseRecipes.

Example:

<Route path='/browse'>
  <Route index element={<BrowseRecipes />} />         // <-- "/browse"
  <Route path=':recipeID' element={<RecipePage />} /> // <-- "/browse/:recipeID"
</Route>

For more information, see:

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese