231

I am using react with react-router. I am trying to pass property’s in a "Link" of react-router

var React  = require('react');
var Router = require('react-router');
var CreateIdeaView = require('./components/createIdeaView.jsx');

var Link = Router.Link;
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;
var RouteHandler = Router.RouteHandler;
var App = React.createClass({
  render : function(){
    return(
      <div>
        <Link to="ideas" params={{ testvalue: "hello" }}>Create Idea</Link>
        <RouteHandler/>
      </div>
    );
  }
});

var routes = (
  <Route name="app" path="/" handler={App}>
    <Route name="ideas" handler={CreateIdeaView} />
    <DefaultRoute handler={Home} />
  </Route>
);

Router.run(routes, function(Handler) {

  React.render(<Handler />, document.getElementById('main'))
});

The "Link" renders the page but does not pass the property to the new view. Below is the view code

var React = require('react');
var Router = require('react-router');

var CreateIdeaView = React.createClass({
  render : function(){
    console.log('props form link',this.props,this)//props not recived
  return(
      <div>
        <h1>Create Post: </h1>
        <input type='text' ref='newIdeaTitle' placeholder='title'></input>
        <input type='text' ref='newIdeaBody' placeholder='body'></input>
      </div>
    );
  }
});

module.exports = CreateIdeaView;

How can I pass data using "Link"?

Geoffrey Hale
  • 10,597
  • 5
  • 44
  • 45
vishal atmakuri
  • 2,333
  • 2
  • 11
  • 5

19 Answers19

196

This line is missing path:

<Route name="ideas" handler={CreateIdeaView} />

Should be:

<Route name="ideas" path="/:testvalue" handler={CreateIdeaView} />

Given the following Link (outdated v1):

<Link to="ideas" params={{ testvalue: "hello" }}>Create Idea</Link>

Up to date as of v4/v5:

const backUrl = '/some/other/value'
// this.props.testvalue === "hello"

// Using query
<Link to={{pathname: `/${this.props.testvalue}`, query: {backUrl}}} />

// Using search
<Link to={{pathname: `/${this.props.testvalue}`, search: `?backUrl=${backUrl}`} />
<Link to={`/${this.props.testvalue}?backUrl=${backUrl}`} />

and in the withRouter(CreateIdeaView) components render(), out dated usage of withRouter higher order component:

console.log(this.props.match.params.testvalue, this.props.location.query.backurl)
// output
hello /some/other/value

And in a functional components using the useParams and useLocation hooks:

const CreatedIdeaView = () => {
    const { testvalue } = useParams();
    const { query, search } = useLocation(); 
    console.log(testvalue, query.backUrl, new URLSearchParams(search).get('backUrl'))
    return <span>{testvalue} {backurl}</span>    
}

From the link that you posted on the docs, towards the bottom of the page:

Given a route like <Route name="user" path="/users/:userId"/>



Updated code example with some stubbed query examples:

// import React, {Component, Props, ReactDOM} from 'react';
// import {Route, Switch} from 'react-router'; etc etc
// this snippet has it all attached to window since its in browser
const {
  BrowserRouter,
  Switch,
  Route,
  Link,
  NavLink
} = ReactRouterDOM;

class World extends React.Component {
  constructor(props) {
    super(props);
    console.dir(props);      
    this.state = {
      fromIdeas: props.match.params.WORLD || 'unknown'
    }
  }
  render() {
    const { match, location} = this.props;
    return (
      <React.Fragment>
        <h2>{this.state.fromIdeas}</h2>
        <span>thing: 
          {location.query 
            && location.query.thing}
        </span><br/>
        <span>another1: 
        {location.query 
          && location.query.another1 
          || 'none for 2 or 3'}
        </span>
      </React.Fragment>
    );
  }
}

class Ideas extends React.Component {
  constructor(props) {
    super(props);
    console.dir(props);
    this.state = {
      fromAppItem: props.location.item,
      fromAppId: props.location.id,
      nextPage: 'world1',
      showWorld2: false
    }
  }
  render() {
    return (
      <React.Fragment>
          <li>item: {this.state.fromAppItem.okay}</li>
          <li>id: {this.state.fromAppId}</li>
          <li>
            <Link 
              to={{
                pathname: `/hello/${this.state.nextPage}`, 
                query:{thing: 'asdf', another1: 'stuff'}
              }}>
              Home 1
            </Link>
          </li>
          <li>
            <button 
              onClick={() => this.setState({
              nextPage: 'world2',
              showWorld2: true})}>
              switch  2
            </button>
          </li>
          {this.state.showWorld2 
           && 
           <li>
              <Link 
                to={{
                  pathname: `/hello/${this.state.nextPage}`, 
                  query:{thing: 'fdsa'}}} >
                Home 2
              </Link>
            </li> 
          }
        <NavLink to="/hello">Home 3</NavLink>
      </React.Fragment>
    );
  }
}


class App extends React.Component {
  render() {
    return (
      <React.Fragment>
        <Link to={{
          pathname:'/ideas/:id', 
          id: 222, 
          item: {
              okay: 123
          }}}>Ideas</Link>
        <Switch>
          <Route exact path='/ideas/:id/' component={Ideas}/>
          <Route path='/hello/:WORLD?/:thing?' component={World}/>
        </Switch>
      </React.Fragment>
    );
  }
}

ReactDOM.render((
  <BrowserRouter>
    <App />
  </BrowserRouter>
), document.getElementById('ideas'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router-dom/4.3.1/react-router-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/4.3.1/react-router.min.js"></script>

<div id="ideas"></div>

#updates:

See: https://github.com/ReactTraining/react-router/blob/0c6d51cd6639aff8a84b11d89e27887b3558ed8a/upgrade-guides/v2.0.0.md#link-to-onenter-and-isactive-use-location-descriptors

From the upgrade guide from 1.x to 2.x:

<Link to>, onEnter, and isActive use location descriptors

<Link to> can now take a location descriptor in addition to strings. The query and state props are deprecated.

// v1.0.x

<Link to="/foo" query={{ the: 'query' }}/>

// v2.0.0

<Link to={{ pathname: '/foo', query: { the: 'query' } }}/>

// Still valid in 2.x

<Link to="/foo"/>

Likewise, redirecting from an onEnter hook now also uses a location descriptor.

// v1.0.x

(nextState, replaceState) => replaceState(null, '/foo')
(nextState, replaceState) => replaceState(null, '/foo', { the: 'query' })

// v2.0.0

(nextState, replace) => replace('/foo')
(nextState, replace) => replace({ pathname: '/foo', query: { the: 'query' } })

For custom link-like components, the same applies for router.isActive, previously history.isActive.

// v1.0.x

history.isActive(pathname, query, indexOnly)

// v2.0.0

router.isActive({ pathname, query }, indexOnly)

#updates for v3 to v4:

The interface is basically still the same as v2, best to look at the CHANGES.md for react-router, as that is where the updates are.

"legacy migration documentation" for posterity

jmunsch
  • 22,771
  • 11
  • 93
  • 114
165

there is a way you can pass more than one parameter. You can pass "to" as object instead of string.

// your route setup
<Route path="/category/:catId" component={Category} / >

// your link creation
const newTo = { 
  pathname: "/category/595212758daa6810cbba4104", 
  param1: "Par1" 
};
// link to the "location"
// see (https://reacttraining.com/react-router/web/api/location)
<Link to={newTo}> </Link>

// In your Category Component, you can access the data like this
this.props.match.params.catId // this is 595212758daa6810cbba4104 
this.props.location.param1 // this is Par1
Shivang Patel
  • 157
  • 1
  • 3
  • 13
Chetan Sisodiya
  • 1,651
  • 1
  • 9
  • 3
  • 2
    exactly what I want. – gramcha Apr 09 '18 at 12:01
  • 14
    This answer is very underrated. It isn't obvious but the documentation mentions this https://reacttraining.com/react-router/web/api/Link/to-object. It advises to pass data as a single object marked 'state' – sErVerdevIL Apr 28 '18 at 05:40
  • 23
    This is the best answer to this question. – Juan Ricardo Jun 22 '18 at 03:04
  • Been dealing with drama for way too long and this totally worked! V4 – Mike Jul 11 '18 at 15:22
  • This is the best answer. – PriyaAnil Aug 13 '18 at 08:34
  • 1
    In the path attribute shouldnt be "/category/595212758daa6810cbba4104" instead of mapping to article??? – Camilo Aug 28 '18 at 12:27
  • Worth noting that "pathname" cannot be a passed-in variable, only an in-line string. Don't know the reason but that's the only way works for me. – Halyna Rubashko Apr 30 '19 at 02:46
  • for me param1 isn't available in location.param1. Instead I wrapped param1 inside state attribute like { pathname: "/category/595212758daa6810cbba4104", state: { param1: "Par1" } }. Now param1 can be accessed as location.state.param1.(By the way I used functional component) – Ravi MCA Jun 19 '20 at 09:31
  • Hi, but is not posible to recover that param1 if i use new tab rigth? (target _blank...), or maybe if i recover part of the currenct query string?, can someone please help me :(. – Juan Ruiz de Castilla Feb 13 '22 at 17:16
  • 5
    This answer, while being great, won't work for V6 of `react-router-dom`. For that, see [this answer](https://stackoverflow.com/a/71064990/6772900). – III_phr Jul 01 '22 at 17:23
  • If you are using a functional component, import the useLocation hook as follows `import { useLocation } from "react-router-dom";`, get the location object `let location = useLocation();` and extract the parameter from `location.param1` – William Ardila Jul 06 '22 at 20:31
39

I had the same problem to show an user detail from my application.

You can do this:

<Link to={'/ideas/'+this.props.testvalue }>Create Idea</Link>

or

<Link to="ideas/hello">Create Idea</Link>

and

<Route name="ideas/:value" handler={CreateIdeaView} />

to get this via this.props.match.params.value at your CreateIdeaView class.

You can see this video that helped me a lot: https://www.youtube.com/watch?v=ZBxMljq9GSE

Alessander França
  • 2,697
  • 2
  • 29
  • 52
  • 3
    Precisely what the documentation says. However, I have a case where DESPITE defining the Route as above, and configuring the LINK to pass the parameter value, the React component class does not have ANY this.props.params values picked up from the URL. Any idea why this might happen? It is like route binding is simply missing. The render() in component class DOES engage, but there is no data passed into the component. – Peter Sep 23 '16 at 22:34
  • 1
    But then in your last example, how do you then pull the 'value' variable in the CreateIdeaView component? – Adrienne Jan 04 '19 at 00:51
38

See this post for reference

The simple is that:

<Link to={{
     pathname: `your/location`,
     state: {send anything from here}
}}

Now you want to access it:

this.props.location.state
Farhan
  • 1,445
  • 16
  • 24
23

as for react-router-dom 4.x.x (https://www.npmjs.com/package/react-router-dom) you can pass params to the component to route to via:

<Route path="/ideas/:value" component ={CreateIdeaView} />

linking via (considering testValue prop is passed to the corresponding component (e.g. the above App component) rendering the link)

<Link to={`/ideas/${ this.props.testValue }`}>Create Idea</Link>

passing props to your component constructor the value param will be available via

props.match.params.value
Kevin K.
  • 542
  • 5
  • 7
18

Inside your Link component do the state

<Link to='register' state={{name:'zayne'}}>

Now to access the item in the page you went to, import useLocation

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

const Register=()=>{

const location = useLocation()

//store the state in a variable if you want 
//location.state then the property or object you want

const Name = location.state.name

return(
  <div>
    hello my name is {Name}
  </div>
)

}

Zayne komichi
  • 408
  • 4
  • 11
15

After install react-router-dom

<Link
    to={{
      pathname: "/product-detail",
      productdetailProps: {
       productdetail: "I M passed From Props"
      }
   }}>
    Click To Pass Props
</Link>

and other end where the route is redirected do this

componentDidMount() {
            console.log("product props is", this.props.location.productdetailProps);
          }
Krishna Jangid
  • 4,961
  • 5
  • 27
  • 33
11

Typescript

For approach mentioned like this in many answers,

<Link
    to={{
        pathname: "/my-path",
        myProps: {
            hello: "Hello World"
        }
    }}>
    Press Me
</Link>

I was getting error,

Object literal may only specify known properties, and 'myProps' does not exist in type 'LocationDescriptorObject | ((location: Location) => LocationDescriptor)'

Then I checked in the official documentation they have provided state for the same purpose.

So it worked like this,

<Link
    to={{
        pathname: "/my-path",
        state: {
            hello: "Hello World"
        }
    }}>
    Press Me
</Link>

And in your next component you can get this value as following,

componentDidMount() {
    console.log("received "+this.props.location.state.hello);
}
gprathour
  • 14,813
  • 5
  • 66
  • 90
9

To work off the answer above (https://stackoverflow.com/a/44860918/2011818), you can also send the objects inline the "To" inside the Link object.

<Route path="/foo/:fooId" component={foo} / >

<Link to={{pathname:/foo/newb, sampleParam: "Hello", sampleParam2: "World!" }}> CLICK HERE </Link>

this.props.match.params.fooId //newb
this.props.location.sampleParam //"Hello"
this.props.location.sampleParam2 //"World!"
FBaez51
  • 482
  • 1
  • 7
  • 12
8

For v6: Attention! state should be outside from to={}

// route setup
<Route path="/employee-edit/:empId" element={<EmployeeEdit />} / >

Link to Component

<Link to={"/employee-edit/1"} state={{ data: employee }} > Edit </Link>

or

<Link to={{
       pathname: "/employee-edit/1",
       search: "?sort=name",
       hash: "#the-hash",
     }}
       state={{ data: employee }} > Edit </Link>

Note: state is outside from to{}, but for v5:

<Link
  to={{
    pathname: "/courses",
    search: "?sort=name",
    hash: "#the-hash",
    state: { fromDashboard: true }
  }}
/>
          

Funtional component:

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

const LinkTest = () => {
  const location = useLocation();
  console.log("Location", location);
  return <h1>Link Test</h1>;
};

export default LinkTest;

Class Component: in order to work with hooks, we need to wrap it in functional component and pass props:

import React, { Component } from "react";
import { useLocation, useParams } from "react-router-dom";

class LinkTestComponent extends Component {
  render() {
    console.log(this.props);
    return <h1>Link Test</h1>;
  }
}

export default () => (
  <LinkTestComponent params={useParams()} location={useLocation()} />
);

Tested with: "react-router-dom": "^6.2.2",

Maruf
  • 354
  • 3
  • 8
7

For v5

 <Link
  to={{
    pathname: "/courses",
    search: "?sort=name",
    hash: "#the-hash",
    state: { fromDashboard: true }
  }}
/>

React Router Official Site

Anand Kapdi
  • 491
  • 5
  • 4
4

In my case I had a function component with empty props and this solved it:

<Link
  to={{
    pathname: `/dashboard/${device.device_id}`,
    state: { device },
  }}
>
  View Dashboard
</Link>

In your function component you should have something like this:

import { useLocation } from "react-router"
export default function Dashboard() {
  const location = useLocation()
  console.log(location.state)
  return <h1>{`Hello, I'm device ${location.state.device.device_id}!`}</h1>
}
3

The simplest approach would be to make use of the to:object within link as mentioned in documentation:
https://reactrouter.com/web/api/Link/to-object

<Link
  to={{
    pathname: "/courses",
    search: "?sort=name",
    hash: "#the-hash",
    state: { fromDashboard: true, id: 1 }
  }}
/>

We can retrieve above params (state) as below:

this.props.location.state // { fromDashboard: true ,id: 1 }
RameshD
  • 912
  • 7
  • 6
3

If you are just looking to replace the slugs in your routes, you can use generatePath that was introduced in react-router 4.3 (2018). As of today, it isn't included in the react-router-dom (web) documentation, but is in react-router (core). Issue#7679

// myRoutes.js
export const ROUTES = {
  userDetails: "/user/:id",
}


// MyRouter.jsx
import ROUTES from './routes'

<Route path={ROUTES.userDetails} ... />


// MyComponent.jsx
import { generatePath } from 'react-router-dom'
import ROUTES from './routes'

<Link to={generatePath(ROUTES.userDetails, { id: 1 })}>ClickyClick</Link>

It's the same concept that django.urls.reverse has had for a while.

KFunk
  • 2,956
  • 22
  • 33
1

I was struggling with this for a few hours and not a single answer in this topic worked for me. Finally I managed to find a solution for React Router 6 in the documentation.

Here is full example:

// App.js

<BrowserRouter>
    <Routes>
        <Route path="/books/:bookId" element={ <BookDetails /> } />
    </Routes>
</BrowserRouter>
// BookDetails.js

import React from "react"
import { useParams } from "react-router-dom"

export default function BookPage() {
    const params = useParams()
    return <div> { console.log(params.bookId) } </div>
}

Note that useParams cannot be called inside a class component so you must use function component (see this answer for details).

eanmos
  • 387
  • 1
  • 6
  • 15
1

In react-router v6 it is with state and useLocation:

<Link to={`/foo`} state={{title: 'foo'}}>
import {useLocation} from "react-router-dom";

const FooPage = () => {
    const location = useLocation()

    return <>
        <h1>{location.state.title}</h1>
    </>
}
export default FooPage;
fabpico
  • 2,628
  • 4
  • 26
  • 43
0

Route:

<Route state={this.state} exact path="/customers/:id" render={(props) => <PageCustomer {...props} state={this.state} />} />

And then can access params in your PageCustomer component like this: this.props.match.params.id.

For example an api call in PageCustomer component:

axios({
   method: 'get',
   url: '/api/customers/' + this.props.match.params.id,
   data: {},
   headers: {'X-Requested-With': 'XMLHttpRequest'}
 })
Abu Shumon
  • 1,834
  • 22
  • 36
0

Updating 25-11-21 Thanks for alex-adestech.mx who wrote above. I was able to transfer the whole object and pull out all the necessary fields from it in send-component :

<Button type="submit" component={NavLink} to={{
        pathname: '/basequestion',
        state: {question} }}
        variant="contained"
        size="small">Take test</Button>

in receive-component:

import { useLocation } from "react-router"
const BaseQuestion = () => {
const location = useLocation();
const {description, title, images} = (location.state.question);
c-sharp-and-swiftui-devni
  • 3,743
  • 4
  • 39
  • 100
0

for V5 (how to pass dynamic variable):

Component, which invokes:

const elementQuery = "/myElements/" + myElement.id + "/properties"

<Link to={{pathname: elementQuery}}>Properties</Link>

Router:

<Switch>
     <Route path="/myElements/:elementId/properties" component={PropertiesPage}/>
</Switch>

How to read dynamic parameter (:elementId) in the target (PropertiesPage) page: property can be read in componentsDidMount() function:

componentDidMount() {
    // Getting id from react router path
    const elementId = this.props.match.params.elementId;
    /*
    * do something with elementId 
    */
}
Benas
  • 2,106
  • 2
  • 39
  • 66