Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

Pass props to the handler component in react-router

react-router has pretty much emerged as a clear win­ner when it comes to rout­ing libraries for React.

How­ever, as you would have already noticed, there isint a very clear way on how to pass down props to your route handlers.

For exam­ple, in the fol­low­ing setup, the top level com­po­nent — App, sim­ply ren­ders what­ever chil­dren are con­fig­ured as per the route.

const App = React.createClass({
    displayName: 'App',

    render() {
        return this.props.children;
    }
});

const Index = React.createClass({
    displayName: 'Index',

    render() {
        return <div>Welcome</div>;
    }
});

React.render((
    <Router history={history}>
        <Route path="/" component={App}>
            <IndexRoute component={Index} />
        </Route>
    </Router>
), document.getElementById('app'));

Now, what if the Index com­po­nent needs a prop to render?

const Index = React.createClass({
    displayName: 'Index',

    propTypes: {
        appName: React.PropTypes.string.isRequired
    },

    render() {
        return <div>Welcome to {this.props.appName}</div>;
    }
});

In the above case, the par­ent App.jsx needs to pass down a required prop to its child. The way to achieve this in react-router is by using React.cloneElement in App.jsx.

const App = React.createClass({
    displayName: 'App',

    render() {
        return React.cloneElement(
            this.props.children, 
            {appName: 'Foo'}
        );
    }
});

Ryan Sukale

Ryan is a UX engineer living in San Francisco, California.

  • tuto­ri­al­hori­zon

    the itself does not trans­fer unknown props to the chil­dren. I usu­ally treat the App.jsx as the entry point for any of the appli­ca­tion logic instead of the route map­pings.
    Another way that I see it is — if the router itself can read the val­ues from some­where and pass it down to the app assum­ing these are mostly sta­tic val­ues, can the App read it from the same place instead of expect­ing it as the prop?

  • David Choy

    This is an excel­lent expla­na­tion, so con­cise! Also see the fol­low­ing doc, which helped me avoid errors by check­ing for chil­dren before cloning (&& state­ment on line 48): https://github.com/reactjs/react-router/blob/3891ee7fcf4e780aa54ce1f68f271f419d2cd1b1/examples/passing-props-to-children/app.js

  • Myron Robert­son

    For some rea­son I found your expla­na­tion sim­ple, but your solu­tion com­pli­cated. I don’t like work­ing that hard, so here’s another eas­ier way to solve the same prob­lem. Add a state prop to the Route com­po­nent to per­sist states to child’s props. For my exam­ple, I’m assum­ing that the code is bro­ken up into sev­eral .jsx/.js files, and you’re using some­thing like Web­pack and Babel for com­pi­la­tion and builds. Sorry for the ES6, it’s eas­ier to write it this way for me…

    ./app.jsx

    import React from ‘react’;
    import {Router, Route, browser­His­tory} from ‘react-router’;
    import {ROUTES} from ‘./constants/routes’;
    import {Ind­ex­Page} from ‘./pages/index_page’;
    import {User­Page} from ‘./pages/user_page’;

    const App = React.createClass({
    // …[setup code such as com­po­nent­Did­Mount, com­po­nent­DidUn­mount, etc.]

    ren­der: func­tion() {
    // just an exam­ple but ide­ally you could just pass down the entire state for your store. Com­po­nents are respon­si­ble for there own data con­sump­tion, or they could be dumb and only han­dle what you pass it. I guess it’s pref­er­ence, but I like smart com­po­nents. This for example

    let ind­ex­Props = {data: {signed_in: true, token: ‘abcd1234’, email: [email protected]}}

    // could be replaced with this (in my world, of course)

    let pro­filePage­Props = {this.props}

    // I don’t believe that the cost is to much. How­ever, if the data set is extremely large then maybe lazy load­ing data using an Ajax client like Super­a­gent with Promise’s would be a bet­ter solution.

    // Here’s the return. I use con­stants to store my routes, so they are all main­tained in a sin­gle file. There is one more prop which I didn’t men­tion called ‘query‘. It takes an object of key value pairs that will be con­verted into a query string. ie. {age: 24} out­puts ?age=24 . So using con­stants are per­fectly fine for stor­ing sta­tic routes that only ever change if your api/app changes.

    return (

    )
    }
    });
    module.exports = {App};

    More info:
    https://github.com/reactjs/react-router/blob/master/docs/API.md#props-1

    If using Google Chrome, there’s an awe­some plu­gin in the Chrome store for React Devel­op­ment, that lets you inspect your com­po­nents in the devel­oper tools. Using that, you’ll be able to inspect your Ind­ex­Page com­po­nent quickly, and view its prop­er­ties. Your state object is nested within:

    this.props.routes[n].state

    Hope this helps any­one else com­ing to this page look­ing for a solu­tion other than React.cloneElement…