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

How to pass init data with server rending in rc-1 #1969

Closed
Yixi opened this issue Sep 16, 2015 · 12 comments
Closed

How to pass init data with server rending in rc-1 #1969

Yixi opened this issue Sep 16, 2015 · 12 comments

Comments

@Yixi
Copy link

Yixi commented Sep 16, 2015

``` 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
@nightwolfz
Copy link

nightwolfz commented Sep 16, 2015

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?

@nightwolfz
Copy link

nightwolfz commented Sep 16, 2015

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}/>,
    });
});
...

@Yixi
Copy link
Author

Yixi commented Sep 17, 2015

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.

@coma
Copy link

coma commented Sep 17, 2015

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?

@nightwolfz
Copy link

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

@coma
Copy link

coma commented Sep 19, 2015

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

@nightwolfz
Copy link

@coma Thanks! Works wonderfully!

@knowbody
Copy link
Contributor

Thanks for answering @coma

@brickyang
Copy link

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

@coma
Copy link

coma commented Nov 5, 2015

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

@brickyang
Copy link

@coma Got it. Thx!

@jwietelmann
Copy link

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?

@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
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

6 participants