(Easy) SSR React conf schedule
In a bid to get you thinking about server side (JavaScript) rendering, I'm running a workshop on Next.js which doesn't just make SSR easy, but it just works out of the box. Though, that said, it all depends on your requirements - and those requirements, I'm sure, can be met, but the "just works out of the box" has varying mileage!
However, building a React based conference schedule with SSR support is straight forward enough that I wanted to write it up by way of example.
Initial setup
The entire system is going to be written in JavaScript, and we'll need node installed along with npm (which comes with node). I'd recommend Node v8 because it supports async/await
which will become useful in the code we write.
I'm assuming we're working on an entirely blank project. To start off, we need a new project directory and the project dependencies.
Start off by creating a file called package.json
containing the following JSON:
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
The in the terminal, run the following commands:
$ npm init -f # create an empty package.json
$ npm install next react react-dom # saves by default
At this point you should have an initialised project that's nearly ready to show you "Hello World".
Next we need a pages
directory (the naming is important) with index.js
:
$ mkdir pages
$ echo "export default () => <div>Hello world</div>" > pages/index.js
Now the project is ready to run, albeit an utterly uninspiring project right now. To browse the project, we need to use npm run dev
(and not start
) to run in development mode:
$ npm run dev
> conf-schedule@1.0.0 dev ./conf-schedule
> next
[ DONE ] Compiled successfully in 1907ms
> Ready on http://localhost:3000
[ ERROR ] Failed to compile with 1 errors
This module was not found:
* react-dom/lib/ReactReconciler in ./node_modules/next/dist/client/next-dev.js
To install it, you can run: npm install --save react-dom/lib/ReactReconciler
β¦then you'll need to use react@15 and react-dom@15 for the time being (Next.js has a couple of pull requests waiting to land to support React v16):
npm install react@15 react-dom@15
Routing simplified
For the conference schedule, I want to have the following URLs handled:
/
the root of the application, showing the timings and session titles/session/:slug
more details about what the talk is and by whom/about
an arbitrary page with venue information, etc
With something like express, I would have to manually define each of these routes in code, and execute the appropriate handler. The way Next does this is with files. We already handle the root path (albeit with "Hello World"), but adding an about page is as simple as creating a file called pages/about.js
.
$ echo "export default () => <div>About my conf</div>" > pages/about.js
Now I can visit the URL http://localhost:3000/about in my browser and it will render. No restart required. No config change. Just works.
The session URL will take a little bit more, but for now, we'll add pages/session.js
and this will read a query string to load each session via the URL, like so: /session?slug=passwords
. This will do for development, but we will need to later make it "pretty".
To give you an more complete example, here's a directory tree for the routes in a Next based application I worked on recently:
pages
βββ 404.js
βββ _error.js
βββ about.js
βββ contact.js
βββ dashboard.js
βββ embed
βΒ Β βββ _single.js
βββ index.js
βββ list
βΒ Β βββ _single.js
βΒ Β βββ new.js
βββ profile
βΒ Β βββ index.js
βΒ Β βββ settings.js
βββ signup.js
βββ tag
βΒ Β βββ _tag.js
βββ terms.js
βββ user
βββ _profile.js
Components
One of the things that has attracted me to React in the last year is the structure it encourages in my code (which previously tended to change from project to project). For the conference schedule, I need two key components:
- Session summary - which we'll loop over for each session
- Session detail
The component for the session summary will look like this:
import classnames from 'classnames';
import format from 'date-fns/format';
import isAfter from 'date-fns/is_after';
export default ({ title, when, slug, isBreak = false }) => {
const finished = isAfter(Date.now(), when);
return (
<a
className={classnames({
Summary: true,
finished,
next: !finished,
isBreak,
})}
href={`/session?slug=${slug}`}
>
<span className="title">{title}</span>
<span className="when">{format(when, 'h:mm A')}</span>
</a>
);
};
A few things to note about the component:
- There's no need for
import React from 'react'
to get the JSX rendering to work, as Next will handle that for me automatically - I'm using classnames and ES6's object shorthand to set different classes for when the session is finished or not.
- I'm using (the superb light alternative to moment) called date-fns for formatting and comparison.
Modifying the pages/index.js
I'll load in some preconfigured data (originally JSON), and loop through each session rendering the session component:
import Summary from '../components/Summary';
import { styles } from '../components/Styles';
import sessions from '../data';
export default function index() {
return (
<div>
<style jsx global>
{styles}
</style>
{sessions.map((session, i) => {
return <Summary key={i} {...session} />;
})}
</div>
);
}
Some closing words
Server Side Rendering (SSR) will quite often fall to the bottom of the priorities in a JavaScript based project, but it's important. It's important to SEO (which tends to have a direct relationship to profits), performance (perceived or otherwise) and even development - as the same code can be used in both client and server side code.
Next.js, I believe, makes SSR for React easy. In fact, that's a lie. It's not easy, but there's nothing really required except perhaps a frame of thinking. Once I start thinking about React as a framework to developβ¦
Drafts may be incomplete or entirely abandoned, so please forgive me. If you find an issue with a draft, or would like to see me write about something specifically, please try raising an issue.