Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass data from a page to another page using react router

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>
    );
  }
}


like image 987
Shadow_net Avatar asked Jan 26 '23 10:01

Shadow_net


1 Answers

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

  • location
  • match
  • useLocation v5
  • useLocation v6
  • useParams v5
  • useParams v6
  • useSearchParams v6.4.0
like image 102
Drew Reese Avatar answered Jan 29 '23 21:01

Drew Reese