21

I am new to react-router and I just started writing an app using react-router V4. I would like to to pass props to components rendered by <Match /> and I am wondering about what's the 'best' or 'proper' way to do so.

Is it by doing something like this?

<Match pattern="/" render={
    (defaultProps) => <MyComponent myProp = {myProp} {...defaultProps} />
}/>

Is this (passing props to components to be rendered by <Match />) even a good practice to do so with react-router or is it an antipattern or something; and if so, why?

Dimitris Karagiannis
  • 8,942
  • 8
  • 38
  • 63

6 Answers6

11

You must use the render prop instead of component to pass on custom props, otherwise only default Route props are passed ({match, location, history}).

I pass my props to the Router and child components like so.

class App extends Component {

  render() {
    const {another} = this.props
    return <Routes myVariable={2} myBool another={another}/>
  }
}

const Routes = (props) =>
  <Switch>
    <Route path="/public" render={ (routeProps) => 
      <Public routeProps={routeProps} {...props}/>
    }/>
    <Route path="/login" component={Login}/>
    <PrivateRoute path="/" render={ (routeProps) =>
       ...
    }/>
  </Switch>
Qwerty
  • 29,062
  • 22
  • 108
  • 136
5
render() {
  return (
    <Router history={browserHistory}>
      <Switch>
        <Route path="/" 
           render={ ()  => <Header 
             title={"I am Title"} 
             status={"Here is my status"}
           /> }
        />
        <Route path="/audience" component={Audience}/>
        <Route path="/speaker" component={Speaker}/>
      </Switch>
    </Router>
  )
}
Qwerty
  • 29,062
  • 22
  • 108
  • 136
im-sunil
  • 434
  • 4
  • 9
1

I'm fairly new to react-router and came across a similar issue. I've created a wrapper based on the Documentation and that seems to work.

// Wrap Component Routes
function RouteWrapper(props) {
  const {component: Component, ...opts } = props

  return (
   <Route {...opts} render={props => (
     <Component {...props} {...opts}/>
   )}/>
 )
}

 <RouteWrapper path='/' exact loggedIn anotherValue='blah' component={MyComponent} />

So far so good

falisse
  • 11
  • 2
  • i tried to implement something similar to this based on another example in github, issues i've had is: a component being rendered when the props are api calls resets the states to empty values – shorif2000 Apr 11 '18 at 12:31
0

I use render in combination with a defined method like so:

class App extends React.Component {
  childRoute (ChildComponent, match) {
    return <ChildComponent {...this.props} {...match} />
  }

  render () {
    <Match pattern='/' render={this.childRoute.bind(this, MyComponent)} />
  }
}
Marc Greenstock
  • 11,278
  • 4
  • 30
  • 54
0

The render prop is meant for writing inline matches, so your example is the ideal way to pass extra props.

Paul S
  • 35,097
  • 6
  • 41
  • 38
  • Is is better to use `component` instead of `render` in this case? – Qwerty Sep 06 '17 at 09:49
  • @Qwerty I just edited my answer to remove that comment. If you are using an inline function, you should also use `render`. Doing that with `component` is really inefficient (you'll be unmounting/mounting a new component every render). – Paul S Sep 07 '17 at 04:34
-1

I'll do it like the following to improve clarity.

const myComponent = <MyComponent myProp={myProp} {...defaultProps} />


<Match pattern="/" component={myComponent} />

By this your router code won't get messed up!.

Pranesh Ravi
  • 18,642
  • 9
  • 46
  • 70