Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Props are not passed by Route to components [v4] #4942

Closed
ilan-schemoul opened this issue Apr 9, 2017 · 22 comments
Closed

Props are not passed by Route to components [v4] #4942

ilan-schemoul opened this issue Apr 9, 2017 · 22 comments

Comments

@ilan-schemoul
Copy link

ilan-schemoul commented Apr 9, 2017

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.

@timdorr
Copy link
Member

timdorr commented Apr 9, 2017

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

@timdorr timdorr closed this as completed Apr 9, 2017
@ilan-schemoul
Copy link
Author

ilan-schemoul commented Apr 10, 2017

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 ?

@ilan-schemoul
Copy link
Author

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

@skosch
Copy link

skosch commented Apr 20, 2017

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 <Route>:
<Route component>
<Route render>
<Route children>

Each is useful in different circumstances. You should use only one of these props on a given <Route>. 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

@jstejada
Copy link

jstejada commented Jul 6, 2017

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

@KyleWMiller
Copy link

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.

@JustFly1984
Copy link

JustFly1984 commented Jul 26, 2017 via email

@acomito
Copy link

acomito commented Jul 29, 2017

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

@skosch
Copy link

skosch commented Jul 29, 2017

@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.

@acomito
Copy link

acomito commented Jul 29, 2017

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

@skosch
Copy link

skosch commented Jul 29, 2017

(... 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.)

@acomito
Copy link

acomito commented Jul 29, 2017

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

@skosch
Copy link

skosch commented Jul 29, 2017

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

@acomito
Copy link

acomito commented Jul 29, 2017

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.

@KyleWMiller
Copy link

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.

@KyleWMiller
Copy link

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

@KyleWMiller
Copy link

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

@Charlie91
Copy link

Charlie91 commented Oct 10, 2017

@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} />}/>

@timdorr
Copy link
Member

timdorr commented Oct 10, 2017

@Charlie91

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

@Charlie91
Copy link

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

@brunoandradebr
Copy link

brunoandradebr commented Oct 16, 2017

what a dirt! would be something like this : <Route path="/" component={MyComponent} MyProp={'bla'} /> and a general data share with all routes :

<BrowserRouter MyData={'bla'}>
<Route..../>
<Route..../>
<Route..../>
</ BrowserRouter>

@CraigglesO
Copy link

CraigglesO commented Oct 17, 2017

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants