FormidableLabs / radium

A toolchain for React component styling.
http://formidable.com/open-source/radium/
MIT License
7.39k stars 308 forks source link

Add explicit docs for Server Side Rendering #487

Open ianobermiller opened 8 years ago

ianobermiller commented 8 years ago

Just so people aren't confused.

aethant commented 8 years ago

+1 please.

bsdo64 commented 8 years ago

+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

content = ReactDOM.renderToString(
      <RoutingContext 
        {...renderProps} 
        radiumConfig={{userAgent: req.headers['user-agent']}} />
    );

ClientSide

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.

oliviertassinari commented 8 years ago

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.

johanneslumpe commented 8 years ago

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

johanneslumpe commented 8 years ago

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.

0x4d6165 commented 8 years ago

@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', {}));
      });
  });
johanneslumpe commented 8 years ago

@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

0x4d6165 commented 8 years ago

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

johanneslumpe commented 8 years ago

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

0x4d6165 commented 8 years ago

@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
johanneslumpe commented 8 years ago

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

0x4d6165 commented 8 years ago

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

johanneslumpe commented 8 years ago

:+1:

JoshuaKGoldberg commented 6 years ago

@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?)