3

I want to create a react app with both client side and server side rendering.

Here is the example:

import styles from './Main.css';

import React, {Component} from 'react';
import Info from './Info/Info';
import Record from './Record/Record'

export default class Main extends Component {
    render() {
        return (
            <div className={styles.main}>
                <div className={styles.mainIn + ' clearfix'}>
                    <div className={styles.mainLeft}>
                        <Info info_num="2012201972"/>
                    </div>
                    <div className={styles.mainRight}>
                        <div className="clearfix mb20">
                            <Record />
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

In this component Main, it needs to be rendered at the client side except <Record />

Component Record

import styles from './Record.css';
import layout from '../../shared/styles/layout.css'

import React, {Component} from 'react';

export default class Record extends Component {
    render() {
        return (
            <div className="float_two">
                <div className={layout.box + ' mr10'}>
                    This is Record!
                </div>
            <div>
        )
    }
}

Here is my question:

I have searched some examples of server-side rendering examples with ReactDom.renderToString and react-router. However, there is no tutorial with both client-side and server-side rendering.

What I want to achieve is that, client first loads and renders Component <Main /> and then loads <Record /> from server-side.

Another question is that, how to load the style module Record.css with renderToString, because I think in this renderToString can just load the html things not the css.

chenatu
  • 827
  • 2
  • 10
  • 22

2 Answers2

2

When people refer to server-side rendering they are usually referring to the initial rendering of the top-level application at a certain route, not individual components.

I'm having trouble understanding your use case is for what you request. Your React application is one big tree of Fragments, so rendering a single component server-side does not really make sense. If you want Record to be a part of React then the client will need to know about it, so why not just render it on the client side as per usual?

If you really need to render it server side then I guess you could build the Record component so that it does an AJAX request and then the html returned could be rendered using https://facebook.github.io/react/tips/dangerously-set-inner-html.html, but I wouldn't recommend it.

My guess is that Record requires some kind of data from the server side and that is why you want to render it there? Instead just fetch that data as JSON and use that to render the component client side.


Having read your comments, I know what you are trying to do. What you want is to dynamically load content (not rendered html) from the server in response to some event (scrolldown, button click or whatever). React is very good at this. By changing the state (i.e. what Records there are) of your application, React will take care of rerendering efficiently.

This is a very simple application. It starts by having 2 items (foo and bar) that should be rendered. In response to an action (button click in this case) more data is loaded into the state and thus rendered to the page. All you need to do is modify this so that instead of the setTimeout you do an AJAX call to your backend to get the actual data.

Live version here: https://codepen.io/dpwrussell/pen/qadrko

class Application extends React.Component {

  constructor(props) {
    super(props);

    // Start with 2 records
    this.state = {
      records: [
        {
          name: 'foo',
          description: 'Some foo'
        },
        {
          name: 'bar',
          description: 'Some bar'
        }
      ]
    };

    // Bind handlers
    this.loadMoreRecords = this.loadMoreRecords.bind(this);
  }

  // Method to call which gets more records on demand
  // Here I just use setTimeout and some static data, but in your case
  // this would be AJAX to get the data from your server where the callback
  // would do the setState. I use a 2 second delay to exaggerate a delay getting
  // the data from the server.
  loadMoreRecords() {
    setTimeout(() => {
      this.setState({
        records: this.state.records.concat([
          {
            name: 'hello',
            description: 'Some newly loaded hello'
          },
          {
            name: 'world',
            description: 'Some newly loaded world'
          }
        ])
      })
    }, 2000);
  }

  // Method to render whatever records are currently in the state
  renderRecords() {
    const { records } = this.state;
    return records.map(record => {
      return (
        <li>{ `${record.name} - ${record.description}` }</li>
      );
    })
  }

  // React's render method
  render() {
    return (
      <div>
        <h1>List of Records Page</h1>
        <ul>
          { this.renderRecords() }
        </ul>
        <input type='button' onClick={this.loadMoreRecords} value='Load more Records' />
      </div>
    );
  }
}

/*
 * Render the above component into the div#app
 */
ReactDOM.render(<Application />, document.getElementById('app'));
dpwr
  • 2,732
  • 1
  • 23
  • 38
  • I want both client and server side rendering for async loading components. Client initially renders the main framework of react app and then loads the sub-components from server. – chenatu Sep 08 '16 at 01:58
  • Yes, I understand that, but that is not how React works. Perhaps if you gave more context and explained why client side rendering of Record is not going to work for you. – dpwr Sep 08 '16 at 02:08
  • Here is one of my case: there are over 100 components in React App. I do not want them rendering at first time, While they are rendered as the user drag down the page in the browser with some triggered events. Most of the users mainly focus on the first few components. So I think this could save brandwidth and cpu times. – chenatu Sep 08 '16 at 05:39
  • So that is exactly what React is good at, I have updated my answer. The key here is that client side React should always be doing the rendering, but you get the content that needs to be rendered, from the server. In the above case I simulate the AJAX call with a setTimeout. – dpwr Sep 08 '16 at 13:25
-1

Using css-modules-require-hook. It's similar to babel-register but for .css file. Basically, it transforms your require('Record.css') to a javascript Object base on your hook config. So your hook config should be same as your webpack css-loader config.

Put it in the entry file of your server.

const hook = require('css-modules-require-hook');

hook({/* config */});
Caojs
  • 175
  • 7