Understanding React Serverside Rendering — Part 2

How To Use NextJS to Render React on the Server

Rajat S
Bits and Pieces

--

This is the Part 2 of a 2 Part Series on React Serverside Rendering. Click here to read Part 1.

In Part 1, we set up a simple React Project and installed the dependencies. We also installed NextJS, and we saw how Next can easily create new routes to different pages in our app.

After that, we created a custom UI theme for the app using Material-UI, and then we rendered into our app. If you were able to do all these error-free, you should get something like this:

As you can see, the App only has a simple header component. When I started writing this post, I had no idea what I wanted this app to actually be about. So as of right now, I am planning to create a web app that renders a list of buttons, each pointing to a new page.

Let’s start by creating a new JS file containing our app’s data.

It’s recommended to use Bit to make your components reusable, so they can be shared, discovered, used and developed across all your projects. It’s a useful way to save time, collaborate and build with components. Give it a try.

Data File

In this section, we will create a new file that will contain an object consisting of a few items. Right now, I have decided to create an object which will contain a list of all the movies of Marvel Cinematic Universe, starting from “Captain America” to “Captain Marvel”.

Since this is going to be a long list, containing each movie’s title, rating, starring, directors and more, I am not going to make this post any longer by posting it here. Instead, I have created a gist from you can take this list of movies and paste it in your project’s root directory, inside a new file named movies.js.

Click here to get the code for movie.js file

Data Into The App

In this section, we will take the data from movie.js file and render it into the app.

To do that, I am going to use the Card component from material-ui. And instead of rendering a normal button, I am going render a RaisedButton component, which is also available to us through material-ui. So lets import both of them into the pages/index.js file.

import {Card,CardHeader,CardText} from 'material-ui/Card';
import RaisedButton from 'material-ui/RaisedButton

We are getting ahead of ourselves here. We also to tell this file where to get the list of movies from. To do that, import the list into index.js as Movie.

import Movie from '../movie';

Now use the Card component to create cards inside the Index component as shown below:

const Index = () => {     
return (
<div>
<Header />
{Movie.map(x =>
<Card key={x.id}>
<CardText>
<RaisedButton label={x.title} fullwidth={true} primary={true}/>
</CardText>
</Card>
)}
</div>
)
}
export default customMaterialUI(Index);

The should will look something like this:

I have also changed the title of my app to make it more relatable to the rest of the app. You can do that as well by making a small change in the Header.js file.

import AppBar from 'material-ui/AppBar';
const Header = ({ title = 'Marvel Cinematic Universe Timeline'}) =>
<AppBar title={title} showMenuIconButton={false} />
export default Header;

Creating Custom Routes Using Next and Express

Right now, we have created a lot of button components in our app. But if we click them, nothing happens. I want each of these buttons to take me somewhere else.

To do this, we can set up our own server configuration inside Next. Lets start doing that by creating a new file named server.js inside the root directory of the app.

In this file, we will need to import express and next. We will also need to define a couple of things, such as the port, dev, app, and handle. dev will tell our server that the environment we are currently in is development and not production.

const express = require('express');
const next = require('next');
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production';
const app = next({dev});
const handle = app.getRequestHandler();

We can now start configuring our server. All the server-related code will be wrapped inside the app.prepare() function. This will allow us to use Next’s features, even though we are no longer going to use Next’s built-in server.

We will start by creating a const named server and set it to the value of express(). We can then use server to define different routes within the app. Let’s start by creating a route named /marvel. I am going to define this route as the default route, so that even when a user enters the usual URL of localhost:3000, the server will automatically append /marvel to the URL.

app.prepare().then(() => {
const server = express();
server.get('/marvel', (req, res) => app.render(req, res, '/'));
})

We can also enforce this URL redirection by telling our server to redirect any user that enters the old URL — the one without any text appended to it.

server.get('/', (req, res) => res.redirect(301, '/marvel'));

Finally, we can setup one last route that will handle all other requests that can be made to our server.

server.get('/*', (req, res) => handle(req, res));

But we are not done yet. After setting up the routes, we still need to tell the app where to listen for the HTTP requests.

server.listen(port, err => {
if(err) throw err
console.log(`Listening on http://localhost:${port}`)
});

One last thing left to do in this section. Our app is still using Next’s built-in server. We need to tell it use the Node server instead and use the configurations that we have just written.

So go to the package.json file and change the dev script to:

"dev": "node server.js"

If you re-run the npm run dev command on your terminal, you will see that the app is running and the default URL is localhost:3000/marvel. If you change /marvel to something like /blah which we have not defined, Next will handle it for us like this:

Route Navigation using Next

In this section, we will continue configuring our custom ExpressJS server. We will now create additional routes that we will use to navigate to a new page for each button in the app.

Back in the server.js file, create another route called /marvel/:id by defining a GET request.

This GET request will use the render function and pass in /movie as another parameter. We will then set up the route to send the id for each “movie” using the request query object. We use Object.assign call to pass the id parameter inside the req object.

server.get('/marvel/:id', (req, res) => {
return app.render(req, res, '/movie', Object.assign({id: req.params.id}, req.query))
})

We also need to define the /movie route. Doing this will allow us to handle calls to each of the movies. Right now, we need to make sure that the movie page loads when individual blog post is requested. Use an if statement to tell the app to redirect to the /marvel/:id blog, only if an id is present.

server.get('/movie', (req, res) => {
if(req.query.id) return res.redirect(`/marvel/${req.query.id}`);
res.redirect(301, '/marvel');
});

We are done working on routes. All that is left to do is to is to make some changes to the index.js file to add a link to each of the buttons. First, we will import the Link component from the next/link library.

import Link from `next/link';

The use the Link component as a wrapper around the RaisedButton. Inside the Link component, add a href attribute to pass the id parameter to our route. Also add the as attribute to tell the app how we want the route to be displayed in the browser.

<Link href={`/movie?id=${x.id}`} as={`/marvel/${x.id}`}>
<RaisedButton label={x.title} fullWidth={true} primary={true}/>
</Link>

Finally, we need to implement a new page that the app will take us to when we click on a button. So create a new file inside the pages folder named movie.js file and write the following code:

import Header from '../components/header';
import customMaterialUI from '../shared/MUI/customMUI';
const Movie = ({ title = 'The Movie Details Will be Shown Here!'}) =>
<div>
<Header/>
<h2>{title}</h2>
</div>;
export default customMaterialUI(Movie);

Rerun the npm run dev command in your terminal, click on any of the buttons, and you should get something like this:

Conclusion

In this series, we used NextJS to create a React App that was rendered on the Server-side instead of Client-Side. But one needs to ask themselves: How did this help us?

By employing SSR with NextJS, we:

  • Eliminated the need for the client to download JavaScript code, since the HTML was already ready in the response.
  • Provided users with an initial render of the application’s view while the code was loading in the background. You can usually see this happening in mobile apps like Facebook and Twitter, where the user will get a barebones UI design on their screen while the app gets all the requested data.

NextJS also made it easier for us to define custom routes on the server.

Another great thing about NextJS is Hot-Module Replacement. So instead of having to reload the browser everytime we made some change in our code, all we had to do was just save the code, and NextJS would automatically update the changes in the browser.

I hope these posts helped you understand the amazing usefulness of NextJS and ServerSide Rendering in React. We can do a lot more with Next. These two posts were only a starting step to SSR.

--

--