React-router: Props are not passed by Route to components [v4]

Created on 10 Apr 2017  Â·  22Comments  Â·  Source: ReactTraining/react-router

Hello,
I use React-route@v4, I have inside my Router :

<Layout searchBar>
    <Route path="/" render={props => <LandingPage {...props} />} />
</Layout>

My layout contains a components which has a component which has a searchBar. I want the content of the searchBar to change the content of a component of LandinPage.
I don't know the best way but I end up with a solution which makes LandingPage having the searchRequest. Now the variable climbed up to the parent component I need to make the variable going down to DrugsList. So my idea was to give to the children component of the layout the prop searchRequest by replacing {children} with :

{React.cloneElement(children, {
    searchRequest,
})}

However <Route path="/" render={props => <LandingPage {...props} />} /> keeps the props for him and doesn't want to give'em to LandingPage so how should I do ?
Actually I'm not only open to understand how making Route passing props to its component but also by finding another way (if you think it's better) to make my components communicating.

Most helpful comment

I just ran into a similar issue while migrating to v4 and pulled my hair out for quite a while. The docs clearly state that Route children get props too, so cloneElement should be the default behaviour. Can we re-open this?

Route render methods

There are 3 ways to render something with a :


Each is useful in different circumstances. You should use only one of these props on a given . See their explanations below to understand why you have 3 options. Most of the time you’ll use component.

Route props

All three render methods will be passed the same three route props

  • match
  • location
  • history

All 22 comments

You would need to wrap Route in your own component that passes through its props to the render function directly. Basically, how NavLink works: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/NavLink.js

Well, it worked :

const LandingRoute = ({ searchRequest }) => (
  <Route
    path="/" children={() =>
    <LandingPage searchRequest={searchRequest} />}
  />
);

Meteor.startup(() => {
  render(
    <Router history={history}>
      <Switch>
        <Route path="/">
          <Layout searchBar>
            <LandingRoute />
          </Layout>
        </Route>
      </Switch>
    </Router>, document.getElementById('app'));
});

Why Route doesn't pass props by default though ?

I ended up creating a PorousRoute, it's a reusable component which always pass props to its children :

import React from 'react';
import Route from 'react-router';

export default function ({ children, ...props }) {
  return (
    <Route path={props.path}>{React.cloneElement(children, props)}</Route>
  );
}

I just ran into a similar issue while migrating to v4 and pulled my hair out for quite a while. The docs clearly state that Route children get props too, so cloneElement should be the default behaviour. Can we re-open this?

Route render methods

There are 3 ways to render something with a :


Each is useful in different circumstances. You should use only one of these props on a given . See their explanations below to understand why you have 3 options. Most of the time you’ll use component.

Route props

All three render methods will be passed the same three route props

  • match
  • location
  • history

hi all! just wondering if there any updates on this issue? is this the expected behavior?

I am also having trouble passing props into the render prop of . My confusion comes in where I'm supposed to declare the array of props to be inserted into the router line component.

I could recommend to declare props in react-redux connect
mapStateToProps

2017-07-26 8:58 GMT+08:00 Kyle Miller notifications@github.com:

I am also having trouble passing props into the render prop of . My
confusion comes in where I'm supposed to declare the array of props to be
inserted into the router line component.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/ReactTraining/react-router/issues/4942#issuecomment-317915656,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACJseYPjRjFDk-7Xdtn7x6LVlJoW8qp-ks5sRo8rgaJpZM4M4L1Z
.

Is there no way to do this?

  render(){

    if (this.props.data.loading) {
      return <LoadingScreen />
    }

    return (
      <div className='public-layout'>
          <Switch>
            <Route exact path='/' component={ SignupPage } {...this.props} />
            <Route exact path='/login' component={ LoginPage } {...this.props} />
          </Switch>
      </div>
    );
  }

@acomito that's not really the same thing. You can achieve that, for example, by using render={() => <SignupPage {...this.props} />} instead of component={...}. But this issue is about the router-specific props (location etc.) not getting injected automatically.

@skosch Thanks for the quick response. That's the answer I needed to track down. Sorry to clog up the wrong thread!

(... or even just <Route ...><SignupPage {...this.props /></Route> would work for you too – but again, the problem is that SignupPage wouldn't get access to props.location etc.)

i see... so to get props.location we need to do React.clone for each route?

Well we shouldn't have to, thus this issue ... :wink:

True. Yeah one of the pages (SignupPage) has on it.. so I can get my this.props.data there with your fix, but am getting this error still:

Failed context type: The context router.push is marked as required in Link, but its value is undefined.

I found a solution to this issue
<Router path="/somePath" render={() => <SomeComponent someProp={prop} />} />

The docs make things overly complicated. Just think of it as writing a component like you would in any other location.

I'm just using the implicit return, anything more complicated doesn't seem to work

From here you still have access to this.props.someProp inside the child component

@KyleWMiller, this is the most simple way to pass props, but bad thing is that when i use it i can't see "match.params" property.
So, for me it works great with simple routes, but not with routes like that
<Route exact path="/conceptions/:id" name="Conception" render={() => <Conception wtf={"wtf"} {...this.props} />}/>

@Charlie91

<Route exact path="/conceptions/:id" render={({ match }) => <Conception match={match} {...this.props} />}/>

@timdorr yeah, it seems i made a mistake i have found it already.
thank you for fixing me!

what a dirt! would be something like this : and a general data share with all routes :




I also tried this.

// @flow
import React, { Component } from 'react';
import { observer }         from 'mobx-react';

/** Modules **/
import MainStore from './MainStore';

/** Stylesheets **/
import './App.css';

@observer
class App extends Component {
  mainStore: MainStore;
  constructor() {
    super();
    this.mainStore = new MainStore();
  }

  render() {
    const { children } = this.props;

    return (
      <div className="App">
        {React.cloneElement(children, { api: this.mainStore.api })}
      </div>
    );
  }
}

export default App;

This doesn't work in react-router v4, but DOES work in react-router v3. -_-
I like dom better htough, oh well.... I am adding a comment because if this get's resolved I'll go back to v4

edit -
https://stackoverflow.com/questions/43469071/react-react-router-dom-pass-props-to-component
great explanation here.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andrewpillar picture andrewpillar  Â·  3Comments

ryansobol picture ryansobol  Â·  3Comments

tomatau picture tomatau  Â·  3Comments

jzimmek picture jzimmek  Â·  3Comments

sarbbottam picture sarbbottam  Â·  3Comments