125

We could navigate to different path using

this.props.router.push('/some/path')

Is there a way to send params (object) along when navigating?

There are other options I can think of, but wonder if passing object is possible at all?

  • I could embed id of the object and refetch the object from server from the new page.

  • Or I could store the object in global storage like redux store. (This object needs to be removed from the store soon. So I'm thinking it might not be good to put it there in the first place)

Cœur
  • 37,241
  • 25
  • 195
  • 267
eugene
  • 39,839
  • 68
  • 255
  • 489

10 Answers10

246

The current answers are outdated.

React Router 6:

Use the useNavigate hook:

const navigate = useNavigate();
navigate('/other-page', { state: { id: 7, color: 'green' } });

Then, you can access the state data in '/other-page' via the useLocation hook:

const {state} = useLocation();
const { id, color } = state; // Read values passed on state

React Router 4 or 5:

Call history.push, and pass an object as the 2nd param to pass state:

props.history.push('/other-page', { id: 7, color: 'green' }))

Then, you can access the state data in '/other-page' via:

props.location.state

Treycos
  • 7,373
  • 3
  • 24
  • 47
Cory House
  • 14,235
  • 13
  • 70
  • 87
  • 1
    If another page push other state such as `{size: 'big'}`, all the state stored will be replaced by this `{size: 'big'}` , how to keep the previous state when pushing another state effectively? – Liuuil Dec 04 '18 at 02:01
  • how do I access the state data from /other-page? – Suleka_28 Aug 14 '19 at 06:37
  • @Suleka_28 - I just added that info to the answer. – Cory House Aug 15 '19 at 11:41
  • wow, thanks a ton @CoryHouse for updating till date ... I wish docs had this kind of e.g. tbh – KcH Aug 28 '22 at 11:16
  • @CoryHouse I am just wondering when we initialize `hook` is it good idea to use `singleTon pattern` instead of initializing in each file For example : >`const {pathname} = useLocation(); ` **inside my login page** which after login I have to check if `userRequestedUrl` is define or not Again I have to initialize the `hook` to grab this value in `login` page `const {state}= useLocation(); console.log(state.userRequestUrl)` is it good idea to use `singleTon pattern here`? – Azhar Uddin Sheikh Nov 18 '22 at 12:26
  • This way it will show up in the url which is impractical if its objects or long texts. How would one pass them? – Martin Eckleben Mar 14 '23 at 11:24
  • @MartinEckleben - If it's not practical for the URL, you should probably persist the data to to a DB. Doing so assures the user doesn't lose a large amount of content as well. – Cory House Mar 15 '23 at 12:49
108

React Router uses location objects. One of the properties of a location object is state.

this.props.router.push({
  pathname: '/other-page',
  state: {
    id: 7,
    color: 'green'
  }
})

On the page that is navigated to, the current location will be injected into the component whose route matched, so you can access the state using this.props.location.state.

One thing to keep in mind is that there will be no state if a user navigates directly to the page, so you will still need some mechanism to load the data when it does not exist.

Paul S
  • 35,097
  • 6
  • 41
  • 38
  • 23
    did you get any solution for this **One thing to keep in mind is that there will be no state if a user navigates directly to the page, so you will still need some mechanism to load the data when it does not exist.** – Anil Jul 19 '17 at 13:40
  • Also interested in how to gracefully handle the scenario when user directly navigate to the route and state is not defined. Ideally it would render loading component and then only when the data is available pass it to the component as props so the component behavior can always assume the required state exists at the time it needs it – Matt Mazzola Sep 17 '17 at 01:13
  • 2
    @MattMazzola I'm not sure there is a "graceful" way, but I would just have default props and use `componentWillMount` or `componentDidMount` to fetch the data. I've moved away from using `location.state` when possible. – Paul S Sep 17 '17 at 05:18
  • @Anil is there a solution to that ? – Gaurav Kumar Jan 31 '20 at 09:16
  • 1
    So let's say we have **PageA** that requests the data, when the server responds back, PageA redirects to **PageB** and passes on the data there. But the user decided to open PageB directly. Here's my solution (in theory, I have yet to implement it): When PageB is opened, it checks if there's a state, if not, it requests the data from the session (whether it's a local or server session), if there is no data there either, it redirects back to pageA. – Jassar Sep 19 '20 at 01:48
  • Every answer here is about using "state". But the original question is centered more on "params". What if I want to navigate to "/entity/:id" so that the page uses "id" parameter? Navigating to "/entity" instead (passing a state along) does not solve that problem, does it? it's a different route. Not even mentioning that maybe I don't want to mess with state representation and just want to pass a param. – Maksim Gumerov Jun 05 '23 at 07:23
9

Best way to pass data to the target Component, just copy paste the code and see the magic, I also explained it in depth.


Remember: in react-router-dom v6 you can use hooks instead.

version 5.X

Let's suppose we have two Components first and second. The first has the link which will target the second component.

The first Component where the link is, by clicking the link you will go to the target path as in my case it is:"/details".

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

export default function firstComponent() {
return(
<>
    <Link to={{
      pathname: '/details',
      state: {id: 1, name: 'sabaoon', shirt: 'green'}
    }} >Learn More</Link>
</>
)
}

Now in the second Component you can access the passed object as:

import React from 'react'


export default class Detials extends React.Component{

    constructor(props){
        super(props);
        this.state={
            value:this.props.location.state,
        }

    }


alertMessage(){
       console.log(this.props.location.state.id);
    }

render(){
return (

    <>
     {/* the below is the id we are accessing */}

      hay! I am detail no {this.props.location.state.id} and my name is 
      {this.props.location.state.name}

      <br/>
      <br/>

 {/* press me to see the log in your browser console */}
<button onClick={()=>{this.alertMessage()}}>click me to see log</button>

    </>

    )
}

}

note:In version 6 of react-router-dom the above method won't work on class components though you can use functional components of react by using useLocation hook and then you can draw the state object through that location in another component.


version 6

How to achieve the same using hooks v6 of react-router-dom

Let's suppose we have two functional components, first component A, second component B. The component A wants to share data to component B.

usage of hooks: (useLocation,useNavigate)

import {Link, useNavigate} from 'react-router-dom';

function ComponentA(props) {

  const navigate = useNavigate();

  const toComponentB=()=>{
navigate('/componentB',{state:{id:1,name:'sabaoon'}});
  }

  return (
   <>
<div> <a onClick={()=>{toComponentB()}}>Component B<a/></div>
</>
  );


}


export default ComponentA;

Now we will get the data in Component B.

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

 function ComponentB() {

    const location = useLocation();
   
        return (

            <>
               
<div>{location.state.name}</div>

            </>
        )
    }

export default ComponentB;
Sabaoon Bedar
  • 3,113
  • 2
  • 31
  • 37
  • but can not find state value after page refresh. how can i solved this? – Md. Shafiqul Islam Nov 13 '22 at 04:38
  • You need to persist the data in local storage, you can do with local storage, and with redux persist a library (https://www.npmjs.com/package/redux-persist) that can help you in your situation. – Sabaoon Bedar Nov 13 '22 at 06:27
8

For functional component and react-router-dom:^5.2.0 let's take a very simple example to make the concept precise

import { useHistory } from "react-router-dom";

  function Sender(){ 
  
  const history = useHistory();

  const goToReceiver = () => {
    history.push("/receiver", { name:'Mr',age:23 });
  }

  return <button onClick={goToReceiver}>Go To Receiver</button>
  }

Now lets see how tha data came to receiver route

  import { useLocation } from "react-router-dom";

  function Receiver(){ 
  
  const location = useLocation();

    return <div>
             <p>{location.state.name}</p>
             <p>{location.state.age}</p>
           </div>
  }
Ruman
  • 936
  • 11
  • 9
8

Their are use cases for sharing data using react-router dom use react-router-dom useNavigate(); than =>

const navigate = useNavigate();
navigate('/toPath', {state: customData})

in other component lets say you want to fetch that data use another hook that is useLocation()

const location = useLocation()
location.state // data will be shared by navigate
Aman Jha
  • 308
  • 4
  • 4
6

You could make a use of useHistory hook of react-router-dom.

Below code is for you to pass your data to the stated route which is "/dashboard".

let history = useHistory();

history.push({
            pathname: '/dashboard',
            state:{
                tags: 'your-value' 
            }
    });

and from the "/dashboard " you can use the useHistory() to receive the above data.

Below code is for you to receive your data.

const Dashboard =()=>{

 let {location} = useHistory();

 return (<>{location.state.tags}</>)
}
Shohin
  • 79
  • 1
  • 3
  • 1
    how to useHistory() to recieve above data, can you please add concrete code to it ? – Salim Shamim Aug 10 '21 at 07:11
  • You can get access to the state that you passed using the useHistory hook. Code sample: let {location} = useHistory(); console.log(location.state) – Shohin Oct 12 '21 at 10:02
4

Passing query parameters when programatically navigation in react router

History objects may be used programmatically change the current location using both history.push and history.replace.

    history.push('/home?the=query', { some: 'state' })

If we pass the history object down into a component as props. Then we can navigate programatically using the react router methods available on the history object.

Now lets assume you are passing down the history object as a prop called 'router'. So it would be referenced inside a component with class based syntax like:

this.props.router

When using push or replace you can either specify both the URL path and state as separate arguments or include everything in a single location-like object as the first argument.

this.props.router.push('/some/path?the=query')

Or you can use a single location-like object to specify both the URL and state. This is equivalent to the example above.

this.props.router.push({
  pathname: '/some/path',  //path
  search: '?the=query' // query param named 'search'
})

Note - Of course make sure that the this.props.router is actually the history object from the react-router api.

therewillbecode
  • 7,090
  • 4
  • 35
  • 42
2

I was not able to get this working with react-router v4+. But the following does work:

//I.e. add navigate using the history stack and pass context as the 2nd parameter
this.props.history.push('/takeTest', {
  subjectsList: this.props.subjectsList.filter(f => f.isChecked === true)
})
adiga
  • 34,372
  • 9
  • 61
  • 83
Richard Strickland
  • 1,771
  • 17
  • 8
0

For sending:

navigate("/success", {
          state: {
            stripeData: res.data,
            products: cart,
          },
        });

For Receiving:

import { useLocation } from "react-router-dom";
  const location = useLocation();
  const data = location.state.stripeData;
  const cart = location.state.products;
-1

if you want to send it in query string

this.props.router.push({
  pathname: '/payment-history',
  query: {
    email: rowData.email
  }
})
adiga
  • 34,372
  • 9
  • 61
  • 83
Ishan
  • 1