React-router: How to pass init data with server rending in rc-1

Created on 16 Sep 2015  路  12Comments  路  Source: ReactTraining/react-router

`javascript
match({routes,location}, (error, redirectLocation, renderProps) => {

    //var locales = 'zh-CN';
    var locales = "en-US";

    var injectData = {
        initData: {
            userInfo: {
                username: req.params.name
            },
            bookmarks:API.bookmarks.getInitBookmarks()

        },
        locales:locales,
        messages:i18n[locales]
    };

    var newProps = assign({},renderProps,injectData);

    console.log(newProps);

    if(redirectLocation){

    }else if(error){

    }else if(renderProps == null){

    }else{
        res.render('default',{
            markup:React.renderToString(<RoutingContext {...newProps}/>),
            inject:'window.__INJECTED = ' +JSON.stringify(injectData)
        });
    }
});

```

I use like this ,but I can't my inject data in component with this.props

Most helpful comment

This is my current approach:

import React from 'react';

class DataWrapper extends React.Component {

    getChildContext () {

        return {
            data: this.props.data
        };
    }

    render () {

        return this.props.children;
    }
}

DataWrapper.childContextTypes = {
    data: React.PropTypes.object.isRequired
};

export default DataWrapper;

so you can use it on the server like:

// data is fetched from mongo or whatever
ReactDOMServer.renderToString(<DataWrapper data={ data }><RoutingContext {...renderProps}/></DataWrapper>)

or on the browser like:

var data    = JSON.parse(document.getElementById('data').innerHTML),
    history = createBrowserHistory();

ReactDOM.render(<DataWrapper data={ data }><Router history={ history }>{ routes }</Router></DataWrapper>, document.getElementById('app'));

What do you think?

All 12 comments

I'd like to know this as well. Currently I'm doing it in a very hacky way:

var routes = function(store){
  return (
    <Route component={App} store={store}>
      <Route path="/" component={Main}/>
    </Route>
  )
};
export default routes;

"store" is what I'm injecting into props.

match({routes: routes(store), location}, (error, isRedirect, renderProps) => {
  ReactDOMServer.renderToString(<RoutingContext {...renderProps}/>),
});

And then I use it like this in my App component

this.props.route.store

This seems very wrong but it works. Can anyone help us out here?

Try the following, it should work :)

Inject "store" through createElement.

...
match({routes, location}, (error, isRedirect, renderProps) => {

    function createElement(Component, props){
        return <Component {...props} {...store} />;
    }

    return doSomething({
        renderProps: <RoutingContext {...renderProps} createElement={createElement}/>,
    });
});
...

The RoutingContext source code
https://github.com/rackt/react-router/blob/master/modules/RoutingContext.js#L55L77

It does't pass the customize props to the Router, only the React-router pre-define props. I tried merge the inject data to the this.props.params like this:

assign(renderProps.params,injectData);

but I think this is a wrong way too.

This is my current approach:

import React from 'react';

class DataWrapper extends React.Component {

    getChildContext () {

        return {
            data: this.props.data
        };
    }

    render () {

        return this.props.children;
    }
}

DataWrapper.childContextTypes = {
    data: React.PropTypes.object.isRequired
};

export default DataWrapper;

so you can use it on the server like:

// data is fetched from mongo or whatever
ReactDOMServer.renderToString(<DataWrapper data={ data }><RoutingContext {...renderProps}/></DataWrapper>)

or on the browser like:

var data    = JSON.parse(document.getElementById('data').innerHTML),
    history = createBrowserHistory();

ReactDOM.render(<DataWrapper data={ data }><Router history={ history }>{ routes }</Router></DataWrapper>, document.getElementById('app'));

What do you think?

How are you passing the props from DataWrapper to the routed components?

@nightwolfz, using context like:

class SomeRoutedComponent extends React.Component {

    constructor (props, context) {

        super(props, context);
        this.state = context.data.someData;
    }
}

SomeRoutedComponent.contextTypes = {
    data: React.PropTypes.object.isRequired
};

export default SomeRoutedComponent;

@coma Thanks! Works wonderfully!

Thanks for answering @coma

@coma where is the id="data" element? Since it's var data = JSON.parse(document.getElementById('data').innerHTML)

@brickyang it's present in my index.html!

My approach is slightly different now that I'm using https://github.com/rackt/react-redux, but the store rehydration on the client side looks pretty similar to the example above.

@coma Got it. Thx!

Does it feel wrong to anyone else that this should be closed because you can hack around the issue using an experimental React feature that's likely to break in future releases? Is there a downside to just allowing arbitrary props to be passed down instead, so that @nightwolfz's createElement method would work?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jzimmek picture jzimmek  路  3Comments

ArthurRougier picture ArthurRougier  路  3Comments

tomatau picture tomatau  路  3Comments

yormi picture yormi  路  3Comments

alexyaseen picture alexyaseen  路  3Comments