1

I'm using react router dom v6. If I write routes like this:

        <Routes>
            <Route path='/posts' element={<Posts/>}/>
            <Route path='/posts/:id' element={<PostDetails/>}/>
            <Route path='/about' element={<About/>}/>
            <Route path='/' element={<Main/>}/>
            <Route path='*' element={<NotFound/>}/>
        </Routes>

it's okay, useParams returning { id: number } in the PostDetails component.

However If I write routes like the following:

            <Routes>
                {routes.map(({path, component}) =>
                    <Route path={path} element={component()}/>
                )}
            </Routes>

useParams returns empty object. Why this happening?

PS: routes is an array of objects containing path & component values. The actual routes value is:

export const routes = [
    {
        path: '/',
        component: Main,
    },
    {
        path: '/about',
        component: About,
    },
    {
        path: '/posts',
        component: Posts,
    },
    {
        path: '/posts/:id',
        component: PostDetails,
    },
]
3
  • 1
    How about if you use {routes.map(({path, component:Component}) => <Route path={path} element={<Component />}/>)} Commented Oct 23, 2022 at 18:59
  • @GabrielePetrioli I'm not sure if I understand what you meaning. What's this Component type? However, it seems like I understand now what's wrong. I tried this <Route path={path} element={React.createElement(component)}/> and it makes the deal Commented Oct 23, 2022 at 19:31
  • It is not a component type, it is just a way to rename the component variable to capitalized form, as React expects components to have a capital first letter. Then you can use it as a normal component. (see MDN docs) Commented Oct 23, 2022 at 19:51

4 Answers 4

1

You're using component as function but they are JSX.Elements.

Try to use as

<Route key={path} path={path} element={<component />}/>

And don't forget to place key.

Sign up to request clarification or add additional context in comments.

1 Comment

This approach <Route path={path} element={<component />}/> causes error saying Property 'component' does not exist on type 'JSX.IntrinsicElements'. I tried this <Route path={path} element={React.createElement(component)}/> and it makes the deal. Thank you for explanation!
0

I think you have a problem because if you don't use <Routes>.

function App() {
    return (
        <Provider store={store}>
            <ThemeProvider theme={theme}>
                <Routes>
                    <PageNav/>
                    <Route key={path} path={path} element={<component />}/>
                </Routes>
            </ThemeProvider>
        </Provider>
    );
}

You can view this link

4 Comments

I'm using <Routes>. See my code snippets, in both cases Routes are wrapped by Routes element.
You're right, put it to me that I added a key
It still doesn't work ?
it works now, thanks. Passing React.createElement(component) makes the deal. But as Gabriele Petrioli mentioned, renaming component to 'Component` also makes it and seems to be a cleaner solution.
0

as @dogukyilmaz mentioned, components are not functions. Passing component value to the Route component prop directly won't make the deal. On the other hand, passing React.createElement(component) makes it.

Comments

0

Issue

The issue is that you are directly invoking a React function component when the route is rendered and not when the route is matched and can correctly access props/contexts/etc as part of the React component lifecycle.

<Routes>
  {routes.map(({ path, component }) =>
    <Route path={path} element={component()} /> // <-- here
  )}
</Routes>

In other words, you are effectively rendering static JSX, i.e. the returned value of directly calling component as a function.

We do not directly call React functions in React, we instead pass them as ReactNodes, a.k.a. JSX.

Solution

Given routes config:

export const routes = [
  {
    path: '/',
    component: Main,
  },
  {
    path: '/about',
    component: About,
  },
  {
    path: '/posts',
    component: Posts,
  },
  {
    path: '/posts/:id',
    component: PostDetails,
  },
];

The mapped components should be passed as JSX, i.e. <Component />.

<Routes>
  {routes.map(({ path, component: Component }) =>
    <Route key={path} path={path} element={<Component />} />
  )}
</Routes>

You may find it easier to align your routes config more along the lines for what react-router-dom uses. Replace "component" property with "element" property and update the element property value to be a ReactNode type.

Example:

export const routes = [
  {
    path: '/',
    element: <Main />,
  },
  {
    path: '/about',
    element: <About />,
  },
  {
    path: '/posts',
    element: <Posts />,
  },
  {
    path: '/posts/:id',
    element: <PostDetails />,
  },
];

...

<Routes>
  {routes.map(({ path, element }) =>
    <Route key={path} path={path} element={element} />
  )}
</Routes>

... or ...

<Routes>
  {routes.map((route) =>
    <Route key={route.path} {...route} />
  )}
</Routes>

Or because you've now effectively declared the routes config correctly as RRD consumes, pass it directly to the useRoutes hook.

import { useRoutes } from 'react-router-dom';
import { routes } from '../path/to/routes';

...

const appRoutes = useRoutes(routes);

...

return (
  ...
  {appRoutes}
  ...
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.