Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-router-dom get id from route with custom components and extra path

I have an app that uses a react-router-config and uses a wrapper component to redirect unauthenticated users.

I have some functionality that requires the use of the route /tasks/:id but I am unable to access the :id value to perform the necessary task lookup.

My routes.js:

import React from "react";
...
const Tasks = React.lazy(() => import("./Components/Tasks"));
...
const routes = [
  {
    path: "/tasks/edit/:id",
    name: "View Task",
    component: Tasks
  }
...
];
export default routes;

Then I have AuthenticatedRoute.js:

import React from "react";
import { Route, Redirect } from "react-router-dom";

export default function AuthenticatedRoute({
  component: C,
  appProps,
  ...rest
}) {
  return (
    <Route
      {...rest}
      render={props =>
        appProps.isAuthenticated ? (
          <C {...props} {...appProps} />
        ) : (
          <Redirect
            to={`/login?redirect=${props.location.pathname}${props.location.search}`}
          />
        )
      }
    />
  );
}

and in the App.js:

import React, { useState, useEffect } from "react";
import { BrowserRouter, Switch, withRouter } from "react-router-dom";
import AuthenticatedRoute from "./components/AuthenticatedRoute/AuthenticatedRoute";
import routes from "./routes";

function App(props) {
...
  return (
    <BrowserRouter>
      <React.Suspense fallback={loading()}>
        <Switch>
            {routes.map((route, idx) => {
              return route.component ? (
                <AuthenticatedRoute
                  key={idx}
                  path={route.path}
                  exact={route.exact}
                  name={route.name}
                  appProps={props}
                  component={props => <route.component {...props} />}
                />
              ) : null;
            })}
        </Switch>
...
      </React.Suspense>
    </BrowserRouter>

Finally I have my Tasks.js:

import React, { useState, useEffect } from "react";
...
function Tasks(props) {
  useEffect(() => {
    onLoad();
  }, []);

  const onLoad = async () => {
    console.log(JSON.stringify(props.match.params));
  };
...

Browsing to localhost:3000/tasks/1. props.match.params is empty in every component up the chain. props.match.params.id is undefined. I have also tried match with {match.params.id} but that is also undefined at every component.

I can see props.location.pathname but that is the full path and I would have to manually get the last segment. I can't get it to automatically grab the :id from the url.

EDIT Turns out my example was too simplified, which actually helped me identify the issue. In my previous version when I had the route:

  {
    path: "/tasks/:id",
    name: "View Task",
    component: Tasks
  }

everything actually works fine using useParams I am able to get the :id value. What I actually have in my app and what seems to be breaking it is adding an additional directory to the path:

  {
    path: "/tasks/edit/:id",
    name: "View Task",
    component: Tasks
  }

I am not sure how this makes a difference, but having the extra /edit seems to break the useParams

like image 385
an00b Avatar asked Nov 18 '19 23:11

an00b


2 Answers

react-router-dom provides some handy hooks. In your case, I'd suggest useParams() (link to docs)

import { useParams } from 'react-router-dom';

function MyComponent {
  let { id } = useParams();

  return (<p>{id}</p>);
}

I'd also probably opt for not using withRouter if you will be using the hooks provided by React Router

like image 93
Martin Avatar answered Nov 10 '22 07:11

Martin


Martins answer is correct and works for functional components. I had the same problem, however I was using a class component (class Company extends Component) and Martins answer did not work for that case. If you have a class component you can do:

import { withRouter } from 'react-router-dom'

class MyComponent extends React.Component {

    componentDidMount() {
        // here you have the id
        const id = this.props.match.params.id;
      }

}

export default withRouter(MyComponent);
like image 27
jakobinn Avatar answered Nov 10 '22 09:11

jakobinn