Is it possible to use Template literal for Component name in React?

Viewed 992

it may be weird, but I want to dynamically route in ReactJs. So, I tried using Template literal for generating the Component name, but its not working. Any idea how its done? or is it not allowed?

<Routes>
{
    Object.keys(Nav_items).map((key,index)=>{
    <Route path={`/${pageNav[key]}`} exact element={<`$(pageNav[key])`/>} ></Route>)
}
<Route path={'/home'}  exact element={<HomePage/>} ></Route>
</Routes>

update: including the whole file

import './Navbar.css'
import {Route, Routes, Link} from 'react-router-dom'
import ElectronicsPage from '../SubPages/ElectronicsPage/ElectronicsPage'
import FashionPage from '../SubPages/FashionPage/FashionPage'
import BestPage from '../SubPages/BestPage/BestPage'
import FurnituresPage from '../SubPages/FurnituresPage/FurnituresPage'
import GamingPage from '../SubPages/GamingPage/GamingPage'
import GroceriesPage from '../SubPages/GroceriesPage/GroceriesPage'
import HomeAppliancesPage from '../SubPages/HomeAppliancesPage/HomeAppliancesPage'
import Mainpage from '../Homepage/MainPage'
import HomePage from '../Homepage/Homepage'


const Navbar=()=>{


    let Nav_items={"Best Sellers":["Redmi Note 7 Pro", "Mac Pro 2","LG TV 5", "Airtel Data Card"],
                "Electronics":["Mobiles","Laptops","Accessories","Smart Devices"],
                "Fashion":["Men's Casual wear","Women's Casual wear","Men's Formal wear", "Children's wear","Accessories"],
                "Gaming":["Gaming Laptops","Build PCs","Gaming Mobiles","Controllers","Games"],
                "Home Appliances":["TVs","Washing Machines","Refrigerators","Ovens","Air Conditioners","Water Purifiers"],
                "Furnitures":["Tables and Desks","Sofas and Chairs","Wardrobes","Beds and Mattresses","Chimneys and Kitchen set"],
                "Groceries":["Vegetables","Masala items","Instant foods","Cosmetics","Hygiene Products"]
            }
        
    const pageNav={"Best Sellers":"BestPage","Electronics":"ElectronicsPage","Fashion":"FashionPage","Gaming":"GamingPage",
                "Home Appliances":"HomeAppliancesPage","Furnitures":"FurnituresPage","Groceries":"GroceriesPage"}

    
    
    return(
        <div>
        <div data-TestId="nav" className="navbar">
            <Link to={'/home'}><img className="option" src={"./option-button.png"} alt="option-button"/></Link>
            {
                Object.keys(Nav_items).map((key,index)=>
                <div className="nav-button">
                    <Link to={`/${pageNav[key]}`}><button>{key}</button></Link>
                    
                <div className="dropdown">
                    {
                    Nav_items[key].map((k,index)=><div className="dropdown">
                    <button>{k}</button></div>)
                    }
                </div>
                </div>
                )
            }
            </div><div style={{"display":"block"}}>
            <Routes>
            <Route path={'/home'}  exact element={<HomePage/>} ></Route>
            <Route path={'/BestPage'}  exact element={<BestPage/>} ></Route>
            <Route path={'/ElectronicsPage'}  exact element={<ElectronicsPage/>} ></Route>
            <Route path={'/FashionPage'}  exact element={<FashionPage/>}></Route>
            <Route path={'/GamingPage'}  exact element={<GamingPage/>} ></Route>
            <Route path={'/HomeAppliancesPage'}  exact element={<HomeAppliancesPage/>} ></Route>
            <Route path={'/FurnituresPage'}  exact element={<FurnituresPage/>} ></Route>
            <Route path={'/GroceriesPage'}  exact element={<GroceriesPage/>} ></Route>
            </Routes>
        </div></div>
    
    )
}

export default Navbar;
2 Answers

For this you must compute the component before rendering the JSX.

Choosing the Type at runtime

<Routes>
  {Object.keys(Nav_items).map((key) => {
    const Component = pageNav[key];
    return <Route path={`/${Component}`} element={<Component />} />
  )}
  <Route path={'/home'} element={<HomePage/>} />
</Routes>

This seems to assume that the route path and component to be rendered are named the same, which may not always be ideal or practical.

I suggest some structure more like:

const Nav_items = [
  {
    path: ".....",
    Component: MyComponent,
  },
  ...
];

Explicitly specify a path and component for each entry:

<Routes>
  {Nav_items.map(({ path, Component }) => (
    <Route key={path} path={path} element={<Component />} />
  ))}
  <Route path={'/home'} element={<HomePage/>} />
</Routes>

Update

Given:

let Nav_items = {
  "Best Sellers": ["Redmi Note 7 Pro", "Mac Pro 2","LG TV 5", "Airtel Data Card"],
  "Electronics": ["Mobiles", "Laptops", "Accessories", "Smart Devices"],
  "Fashion": ["Men's Casual wear", "Women's Casual wear", "Men's Formal wear", "Children's wear", "Accessories"],
  "Gaming": ["Gaming Laptops", "Build PCs", "Gaming Mobiles", "Controllers", "Games"],
  "Home Appliances": ["TVs", "Washing Machines", "Refrigerators", "Ovens", "Air Conditioners", "Water Purifiers"],
  "Furnitures": ["Tables and Desks", "Sofas and Chairs", "Wardrobes", "Beds and Mattresses", "Chimneys and Kitchen set"],
  "Groceries": ["Vegetables", "Masala items", "Instant foods", "Cosmetics", "Hygiene Products"]
}

None of the Nav_items object keys are the names of any React components you imported:

import ElectronicsPage from '../SubPages/ElectronicsPage/ElectronicsPage';
import FashionPage from '../SubPages/FashionPage/FashionPage';
import BestPage from '../SubPages/BestPage/BestPage';
import FurnituresPage from '../SubPages/FurnituresPage/FurnituresPage';
import GamingPage from '../SubPages/GamingPage/GamingPage';
import GroceriesPage from '../SubPages/GroceriesPage/GroceriesPage';
import HomeAppliancesPage from '../SubPages/HomeAppliancesPage/HomeAppliancesPage';
import Mainpage from '../Homepage/MainPage';
import HomePage from '../Homepage/Homepage';

BUT pageNav appears to have the mapping of the page/link to the component name

const pageNav = {
  "Best Sellers": "BestPage",
  "Electronics": "ElectronicsPage",
  "Fashion": "FashionPage",
  "Gaming": "GamingPage",
  "Home Appliances": "HomeAppliancesPage",
  "Furnitures": "FurnituresPage",
  "Groceries": "GroceriesPage"
}

You are trying to map Nav_items object keys to a value from pageNave, but these values are Strings, not React components.

{Object.keys(Nav_items).map((key) => {
  const Component = pageNav[key]; // <-- String values!!!
  return <Route path={`/${Component}`} element={<Component />} />
)}

To Resolve, fix the mapping in pageNav so the values are the imported React components.

const pageNav = {
  "Best Sellers": BestPage,
  "Electronics": ElectronicsPage,
  "Fashion": FashionPage,
  "Gaming": GamingPage,
  "Home Appliances": HomeAppliancesPage,
  "Furnitures": FurnituresPage,
  "Groceries": GroceriesPage
}

Now const Component = pageNav[key]; should actually refer to a React Component and render fine, but since it's no longer a string, won't work for the route path. You still need a string. I suggest using the key. You may have issues with whitespace, so you may want to strip that out.

{Object.keys(Nav_items).map((key) => {
  const Component = pageNav[key];
  return <Route path={`/${key.replace(/\W/g, '')}`} element={<Component />} />
)}

You can not use template literal string for components.

But you can use this approach for your purpose

<Routes>
{
  Object.keys(Nav_items).map((key,index) => {
    const Component = pageNav[key];
    return (
      <Route path={`/${pageNav[key]}`} exact element={<Component />} />
    )
  })
  <Route path={'/home'}  exact element={<HomePage/>} ></Route>
</Routes>
Related