Radium: Add explicit docs for Server Side Rendering

Created on 6 Jan 2016  Â·  14Comments  Â·  Source: FormidableLabs/radium

Just so people aren't confused.

Most helpful comment

@johanneslumpe / @ianobermiller - are there docs on what Radium will or will not do in SSR? Would be very helpful to at least have an FAQ.

For example: if React SSR is used to generate an .html page that then does _not_ hydrate with client-side JS, will :hover effects still work? _(do you support generating that stylesheet initially?)_

All 14 comments

+1 please.

+1

There are some tips making wrapper #429 or other ways.
But I think they're run out. I could solve the warnings without wrappers.
I have updated 0.16.2 successful by fixing like this.

Serverside

  • Just add radiumConfig where rendering need media query
content = ReactDOM.renderToString(
      <RoutingContext 
        {...renderProps} 
        radiumConfig={{userAgent: req.headers['user-agent']}} />
    );

ClientSide

  • Wrap <StyleRoot /> the top of entry.
let App  = React.createClass({ ... })
App = Radium(App);

let RootApp = React.createClass({
  displayName: 'RootApp',
  render() {
    return (
      <StyleRoot>
        <App {...this.props} />
      </StyleRoot>
    );
  }
});

export default RootApp;

This will solve the warnings and print clean console.

I think that it would be interesting to document where < StyleRoot /> should be used in the rendering tree when we are using radium with react-router or redux.

@bsdo64 Are you sure that that works? It won't even let me render without the StyleRoot. @ianobermiller Is StyleRoot supposed to be used on both server an client? I'm wrapping by top level component in StyleRoot and am passing radiumConfig to the RouterContext, but cannot get rid of the checksum issue.

And just so as I posted this, I got it working. The solution was to just always wrap the top level component within StyleRoot. @oliviertassinari Using redux and react-router: wrap your RouterContext within redux' Provider component. And use StyleRoot in your top-level route handler.

@johanneslumpe For some reason, wrapping my my route handler like so:

// shared/routes.js
 <StyleRoot>
    <Route path="/" component={App} >
      <IndexRoute component={PostContainer} />
      <Route path="/post/:slug" component={PostDetailView} />
    </Route>
 </StyleRoot>

returns an error beginning with: Cannot read property 'need' of undefined.
For context, the part of my server.js that handles the actual server-side rendering is:

// server/server.js
fetchComponentData(store.dispatch, renderProps.components, renderProps.params)
      .then(() => {
        const initialView = renderToString(
          <Provider store={store}>
            <RouterContext {...renderProps} radiumConfig={{ userAgent: req.headers['user-agent'] }} />
          </Provider>
        );
        const finalState = store.getState();

        res.status(200).end(renderFullPage(initialView, finalState));
      })
      .catch(() => {
        res.end(renderFullPage('Error', {}));
      });
  });

@gigavinyl try this:

/// App.js
function App({ children }) {
  return (
    <StyleRoot>
      {children}
    </StyleRoot>
  );
}

export default radium(App);

// shared/routes.js
<Route path="/" component={App} >
  <IndexRoute component={PostContainer} />
  <Route path="/post/:slug" component={PostDetailView} />
</Route>

Furthermore, for whatever reason it didn't work for me to pass in the radiumConfig via RouterContext. I am using the following createElement function to pass it in:

const createElement = (Component, props) => (
  <Component
    {...props}
    radiumConfig={{ userAgent: req.headers['user-agent'] }}
  />
);

So rendering the RouterContext looks like this:

renderToString(
  <RouterContext
    {...renderProps}
    createElement={createElement}
  />,
);

This works like charm for me.

// edit
added decorator to App

@johanneslumpe Hmm, didn't work for me...
For context, I'm using redux and the part of my server.js file that handles server-side rendering is:

    fetchComponentData(store.dispatch, renderProps.components, renderProps.params)
      .then(() => {
        const createElement = (Component, props) => (
          <Component
            {...props}
            radiumConfig={{ userAgent: req.headers['user-agent'] }}
          />
        );
        const initialView = renderToString(
          <Provider store={store}>
            <RouterContext {...renderProps} createElement={createElement} />
          </Provider>
        );
        const finalState = store.getState();

        res.status(200).end(renderFullPage(initialView, finalState));
      })
      .catch(() => {
        res.end(renderFullPage('Error', {}));
      });

and my App.js container is:

import React, { Component, PropTypes } from 'react';
import PostListView from '../container/PostListView/PostListView';
import PostCreateView from '../components/PostCreateView/PostCreateView';
import { connect } from 'react-redux';
import { StyleRoot } from 'radium';
import * as Actions from '../redux/actions/actions';

class App extends Component {
  static propTypes = {
    dispatch: PropTypes.func.isRequired,
    children: PropTypes.object.isRequired,
  }

  render() {
    const { dispatch } = this.props;
    return (
      <StyleRoot>
        <div className="container">
          { this.props.children }
        </div>
      </StyleRoot>
      );
  }
}

export default connect()(App);

I applogize for my n00bie-ness :grin:.

@gigavinyl Can you be more descriptive than "It didn't work"? ;)

@johanneslumpe Upon initially loading the page, I'm met with this error:

Radium: userAgent should be supplied for server-side rendering. See https://github.com/FormidableLabs/radium/tree/master/docs/api#radium for more information.
Either the global navigator was undefined or an invalid userAgent was provided. Using a valid userAgent? Please let us know and create an issue at https://github.com/rofrischmann/inline-style-prefixer/issues

@gigavinyl Can you please try to use the @Radium decorator on your App component? I think it's missing in my example above.

@johanneslumpe Thanks! It works perfectly now with no errors :smile:.

:+1:

@johanneslumpe / @ianobermiller - are there docs on what Radium will or will not do in SSR? Would be very helpful to at least have an FAQ.

For example: if React SSR is used to generate an .html page that then does _not_ hydrate with client-side JS, will :hover effects still work? _(do you support generating that stylesheet initially?)_

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hhimanshu picture hhimanshu  Â·  8Comments

zhangmengxue picture zhangmengxue  Â·  9Comments

pocketjoso picture pocketjoso  Â·  8Comments

rkrishna-codal picture rkrishna-codal  Â·  4Comments

willhalling picture willhalling  Â·  4Comments