Skip to content

Instantly share code, notes, and snippets.

@ugiacoman
Last active June 24, 2022 20:50
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ugiacoman/6760df00bf491c845139b404a7a4afb4 to your computer and use it in GitHub Desktop.
Save ugiacoman/6760df00bf491c845139b404a7a4afb4 to your computer and use it in GitHub Desktop.
SSR + CSR using next.js

Whether your component relies on client-side features or you are using 3rd party components that are not designed for server-side rendering, sometimes you'll want to defer rendering until on the client. For our example, we'll be using react-chart-2 to load a Doughnut chart.

Doughnut

You'll need a next project and to install chart.js + react-chartjs-2.

$ npm install --save chart.js react-chartjs-2  

Let's start off by creating a new page. We'll create a new file clientLoadExample.js and load up a new component. This component will create a variable graph, set it to a span html element and return it. So far, next is handling the state and deciding when to render our component.

// /pages/clientLoadExample.js

import React from 'react'
export default class ClientLoadExample extends React.Component {
  render() {
    let graph;
    graph = <span> Server </span>;
    return graph;
  }
}

Now let's create a flag that will allow us to check whether we are on the server or on the client. We'll access state and set an inClient flag.

export default class ClientLoadExample extends React.Component {
  state = {
    inClient: false
  };
 
  ...
}

After React inserts an instance of a component into the DOM, the componentDidMount() method is triggered. We can use this method to update our inClient flag.

export default class ClientLoadExample extends React.Component {
  state = {
    inBrowser: false
  };
  componentDidMount() {
    this.setState({ inClient: true });
  }  
 
  ...
}

Now we can monitor the state during the rendering of our component. The next time the component is rendered, we'll be able to check our flag; if we are in the client, load our new component. So let's update our render() method.

export default class ClientLoadExample extends React.Component {
...

  render() {
    let graph;
    if (this.state.inClient) {
        var Chart = require( 'react-chartjs-2' );
        graph = <Chart.Doughnut data={data} />;
    } else {
      graph = <span> Server </span>;
    }
    return graph;
  }
}

There you have it! Let's add some data so that our Doughnut doesn't crash! Oh, and here's the full code snippet :)

import React from 'react'

export default class ClientLoadExample extends React.Component {

  state = {
    inClient: false
  };

  componentDidMount() {
    this.setState({ inClient: true });
  }

  render() {
    let graph;
    if (this.state.inClient) {
        var Chart = require( 'react-chartjs-2' );
        graph = <Chart.Doughnut data={data} />;
    } else {
      graph = <span> Server </span>;
    }
    return graph;
  }
}

const data = {
  labels: [
    'Red',
    'Green',
    'Yellow'
  ],
  datasets: [{
    data: [300, 50, 100],
    backgroundColor: [
    '#FF6384',
    '#36A2EB',
    '#FFCE56'
    ],
    hoverBackgroundColor: [
    '#FF6384',
    '#36A2EB',
    '#FFCE56'
    ]
  }]
};
@RaitoBezarius
Copy link

Awesome tip !

@rauchg
Copy link

rauchg commented Nov 17, 2016

Thanks a lot for this write-up. Another way of doing this is to set a property in getInitialProps:

static getInitialProps ({ req }) {
  return { isServer: req ? true : false } 
}

Then you get this.props.isServer

@taylorsmithgg
Copy link

This should be documented somewhere other than a gist.
I spent around an hour today trying to get it working.
Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment