10

Please I need help on react-router-dom, I am new to the library and can seem to find any solution since. I am getting three results from an api call, in which I map over the data to render it on UI, now what I need now is that if I click on a row on one of this list, I want it to take me to a screen showing the details of only that single thing I clicked on.

import React, { Component } from "react";

export default class User extends Component {
  state = { userDetails: "" };

  componentDidMount() {
    axios.get(`https://urlforapi.com`)
    .then(({ data }) => {
      this.setState({
        userDetails: data
      });
    });
  }

  render() {
    const { userDetails } = this.state;
    return (
      <div>
        {userDetails
          ? userDetails.map(info => {
              return (
                <Link to="/home/userDetails">
                  <div key={info.id}>
                    <p>{info.name}</p>
                  </div>
                  <div>
                    <p>{info.age}</p>
                  </div>
                  <div>
                    <p>{info.description}</p>
                  </div>
                </Link>
              );
            })
          : null}
      </div>
    );
  }
}


Sohail Ashraf
  • 10,078
  • 2
  • 26
  • 42
Shadow_net
  • 161
  • 1
  • 4
  • 11

5 Answers5

27

Option 1: Pass Route State

Send the state in the route transition.

  • Using react-router-dom v5

    Declarative Navigation - Link to

    You can pass some state unique to the mapped entry, like info.id along with the route push that happens when the link is clicked. This obfuscates the data from the user as you aren't leaking information out to the ui (i.e. the browser).

    <Link
      to={{
        pathname: '/home/userDetails',
        state: { infoId: info.id },
      }}
    >
    

    Imperative Navigation - useHistory hook

    const history = useHistory();
    
    ...
    
    history.push({
      pathname: '/home/userDetails',
      state: { infoId: info.id },
    });
    

    You can then unpack the state from the location prop/object on the component being returned by that route. Use guards in case a user has navigated to '/home/userDetails' from elsewhere, as state may be undefined.

    If passed route props:

    props.location && props.location.state && props.location.state.infoId
    

    or

    props.location?.state?.infoId
    

    If using function components then you can also use the useLocation React hook:

    const { state: { infoId } = {} } = useLocation();
    

    Edit lucid-kowalevski-uxgs4

  • Using react-router-dom v6

    Declarative Navigation - Link or Navigate components

    The link API changed a bit in v6, the state is now a prop.

    <Link
      to='/home/userDetails'
      state={{ infoId: info.id }}
    >
    

    or using the Navigate component, the spiritual successor/replacement to the v5 Redirect component

    <Navigate
      to="/home/userDetails"
      state={{ infoId: info.id }}
    />
    

    Imperative Navigation - useNavigate hook

    const navigate = useNavigate();
    
    ...
    
    navigate('/home/userDetails', { state: { infoId: info.id } });
    

    You can then unpack the state from the location object on the component being returned by that route. Use guards in case a user has navigated to '/home/userDetails' from elsewhere, as state may be undefined.

    const { state: { infoId } = {} } = useLocation();
    

    Edit how-to-pass-data-from-a-page-to-another-page-using-react-router (forked)

Option 2: Pass Something in the URL path

<Link to={`/home/userDetails/${info.id}`>

or (RRDv5)

const history = useHistory();

...

history.push(`/home/userDetails/${info.id}`);

or (RRDv6)

const navigate = useNavigate();

...

navigate(`/home/userDetails/${info.id}`);

And retrieve the param from the match prop in the returned route component. For example if the route looks like this:

  • Using react-router-dom v5

    <Route path="/home/userDetails/:infoId" component={Detail} />
    

    Then in the component get id from the match route prop:

    props.match.params.infoId
    

    And in the case of function components, the useParams React hook:

    const { infoId } = useParams();
    
  • Using react-router-dom v6

    <Route path="/home/userDetails/:infoId" element={<Detail />} />
    

    There is only the useParams hook in v6, there are no route props.

    const { infoId } = useParams();
    

The user can see this, but you don't have to use the guard pattern to access since by definitions it'll be defined by the route (though infoID can still be defined if the user types in an invalid id).

Option 3: Pass Something in the URL queryString

  • Using react-router-dom v5

    Declarative Navigation - Link to

    <Link
      to={{
        pathname: '/home/userDetails',
        search: `?infoId=${info.id}`,
      }}
    >
    

    Imperative Navigation - useNavigate hook

    const history = useHistory();
    
    ...
    
    history.push({
      pathname: '/home/userDetails',
      search: `?infoId=${info.id}`,
    });
    

    You can then unpack the infoId query param from the location prop/object on the component being returned by that route.

    If passed route props:

    props.location && props.location.search

    or

    props.location?.search

    If using function components then you can also use the useLocation React hook:

    const { search } = useLocation();

    Then create a URLSearchParams object and access the infoId parameter.

    const searchParams = new URLSearchParams(search);
    const infoId = searchParams.get("infoId");
    
  • Using react-router-dom v6

    Declarative Navigation - Link or Navigate components

    The link API changed a bit in v6, the state is now a prop.

    <Link
      to={{
        pathname: '/home/userDetails',
        search: `?infoId=${info.id}`,
      }}
    >
    

    or using the Navigate component, the spiritual successor/replacement to the v5 Redirect component

    <Navigate
      to={{
        pathname: '/home/userDetails',
        search: `?infoId=${info.id}`,
      }}
    />
    

    Imperative Navigation - useNavigate hook

    const navigate = useNavigate();
    
    ...
    
    navigate({
      pathname: '/home/userDetails',
      search: `?infoId=${info.id}`,
    });
    

    You can then unpack the infoId query param from the useSearchParams hook.

    const [searchParams] = useSearchParams();
    const infoId = searchParams.get("infoId");
    

    New in v6.4.0 is the createSearchParams utility function.

    <Link
      to={{
        pathname: '/home/userDetails',
        search: createSearchParams({ infoId: info.id}),
      }}
    >
    

    or

    navigate({
      pathname: '/home/userDetails',
      search: createSearchParams({ infoId: info.id}),
    });
    

But I'm using a React class component

In react-router-dom@6 the route props and withRouter HOC were removed. To access the old "route props" in RRDv6 you'll need to create your own withRouter HOC replacement that can use the React hooks and inject props that can be used in React class components.

import { useLocation, useParams, /* other hooks */ } from 'react-router-dom'; 

const withRouter = WrappedComponent => props => {
  const location = useLocation();
  const params = useParams();
  // other hooks

  return (
    <WrappedComponent
      {...props}
      {...{ location, params, /* other hooks */ }}
    />
  );
};

Decorate the component and access props:

class MyComponent extends React.Component {
  ...

  this.props.location.state;
  this.props.params;
  ...etc...

  ...
};

export default withRouter(MyComponent);

References

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • I don't seem to understand the first option, can you please show some code on how to get this data on that second page. I tried it and it keeps returning "undefined" when I logged my data. – Shadow_net Jan 12 '20 at 10:06
  • I thought I did. I copy/pasted it from the `react-router-dom` docs and tailored it closer to your code, and I included a link to that section. I've updated my answer to include a link to a running codesandbox. If you're seeing "undefined" when trying to access the `location.state` I mentioned to use the guard pattern to ensure the object property path is defined to the state value you need. – Drew Reese Jan 12 '20 at 10:44
  • Can you not pass class instances into useNavigate's state? My private members are all lost when I do so? – sayandcode Aug 10 '22 at 11:29
  • @sayandcode I might need to see a [mcve] to help answer that question. Do you mind creating a new SO post for this question and relevant code? If you do feel free to ping me here with a link to it and I can take a look when available. – Drew Reese Aug 10 '22 at 19:36
  • @DrewReese - I have deleted the comment. I tried to mean that, the guide for react router dom may help with solution in this context and also, I am struggling to pass a state as props from immediate parent to a child in react. I have searched a lot of SO solutions.. but couldn't get an idea. I want to pass a props through `` to a child. `props.location.state` is throwing an error. I am using react router dom v.6.3 – Common Man Aug 19 '22 at 18:05
  • @CommonMan In RRDv6 there are not any route props like there were in v5. You should use the `useLocation` hook to access the `location` object. I'll make this distinction more overt in my answer. – Drew Reese Aug 19 '22 at 18:42
  • Under router v6 you posted a code sandbox which is using react router dom v.5.1. Which is using ` – Common Man Aug 19 '22 at 18:43
  • @CommonMan Woah.... that RRDv5 sandbox was old enough it wasn't organized into my stackoverflow directory. I've updated the RRDv5 sandbox code to be more current, and added a RRDv6 sandbox demo in that section. – Drew Reese Aug 27 '22 at 05:35
0

You can use path params option of react-router-dom .

Example

import React from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'

import Topic from '../topic'

export default function App() {
  return (
    <Router>
      <div>
        <Route path="/topic/:name" component={Topic} />
      </div>
    </Router>
  );
}

Pass the params:

import React, { Component } from "react";
import { Link } from 'react-router-dom'

export default class Topics extends Component {
  render() {
    return <Link to="/topic/someTopicName">Some Topic</Link>;
  }
}

Access router params in the component

import React from 'react'

export default function Topic(props) {
  return <h1>{props.match.params.name}</h1>
}
Sohail Ashraf
  • 10,078
  • 2
  • 26
  • 42
0

This is how you can pass data to navigated component

<Link
  to={{
    pathname: '/home/userDetails',
    state: {infoId: info.id},
  }}
>

And access like this in navigated component

if it's class based component.

this.props.location.state

if it's functional component

props.location.state
akhtarvahid
  • 9,445
  • 2
  • 26
  • 29
0

If your using function component in your react application. You can follow below steps

Main page:

<Link
  to={{
    pathname: '/your/path',
    state: { 
       data: "your data"
    },
  }}
>

In your child page or page you wanted to route:

use useLocation (version 5.+) hook

const emp = useLocation()

console.log(emp)

Output

{ 
   state: { 
       data: "your data" 
   } 
}
Mohan Sai
  • 43
  • 6
0
**Pass the state:**
import { Link} from "react-router-dom";
<Link to="/home/userDetails"  state: { userDetails:'Name'} }>

**Received the state:**
import { useLocation} from 'react-router-dom';
const location = useLocation();
const userDetails= location.state.userDetails;
Thaiyalnayaki
  • 148
  • 1
  • 8