Search code examples
javascriptreactjsreact-routerreact-router-dom

How to merge a router have variable with variables in array in React


I have a config route :

const routers = {
  home: '/',
  category: '/category/:slug',
}

and an array :

array = [
  { id: 1, slug: 'table'},
  { id: 2, slug: 'chair'},
]

I use array.map() to generate a list of NavLink components:

array.map(item => {
  return <NavLink key={item.id} to={routers.category+item.slug}>
    {item.slug}
  </NavLink>
})

But it doesn't work. The result is localhost:3000/category/:slugtable and localhost:3000/category/:slugchair.

The expected result is localhost:3000/category/table.

How can I solve it?


Solution

  • The issue is that for the link target you are using string concatenation.

    to={routers.category+item.slug}
    

    This results in link targets like "/category/:slug" + "chair" which results in string literals "/category/:slugchair" which likely isn't what you expected or have a route path to match.

    react-router exports a path generating utility, oddly enough, named generatePath.

    generatePath interpolates a set of params into a route path string with :id and * placeholders. This can be useful when you want to eliminate placeholders from a route path so it matches statically instead of using a dynamic parameter.

    generatePath("/users/:id", { id: "42" }); // "/users/42"
    generatePath("/files/:type/*", {
      type: "img",
      "*": "cat.jpg",
    }); // "/files/img/cat.jpg"
    

    Use generatePath to take the "/category/:slug" path and the slug param to generate the target path.

    import { NavLink, generatePath } from 'react-router-dom';
    
    ...
    
    array.map(item => (
      <NavLink key={item.id} to={generatePath(routers.category, item)}>
        {item.slug}
      </NavLink>
    ))
    

    The slug property on item will be assigned to the ":slug" route path param.