React.js routing without React Router: itsa-react-server

Marco Asbreuk
Aug 26, 2017 · 4 min read

Itsa-react-server is a MVC framework for building server side rendered single page apps (SPAs) with React.js. In case you missed it: see here.

This article is about how to implement routing to your web application.

Introduction

For those who are new to routing: it is the mechanism that takes care of serving the proper file (or take the right action) after a specific client request.

Itsa-react-server assumes that every page can be requested RESTful with a unique url. We only need to make sure that we bind the urls to the proper views. Because itsa-react-server generates single page applications, referring to those pages from within the web app results into an ajax request, no full page load.

Additionally, itsa-react-server allows you to interact with the server behind the scenes through Ajax requests.

Server side routing

Because itsa-react-server is built upon Hapi.js, its routes are conforming Hapi’s routing principles. Itsa-react-server defined two special methods, which are basic to its functionality:

reply.action

reply.action will invoke a special file inside the actions folder. It is meant to perform some kind of action, like form processing, data storage etc.:
src/routes.js:

[
...
{
method: ‘PUT’,
path: ‘/login’,
handler: function(request, reply) {
const options = {};
reply.action(‘login’, options);
}
},
...
]

This example will invoke the next file:
src/actions/login.js:

const actionFn = async (request, reply, options, lang, manifest) => {
const payload = request.payload,
email = payload.email,
password = payload.password;
// do something
return {
status: 'OK'
}
};
module.exports = actionFn;

Note 1: the action function always gets invoked with 5 arguments.
options is an optional object, defined inside the router: the second argument of reply.action().
lang is the actual language that the user selected; in case internationalization is activated.
manifest is the manifest file; src/manifest.json for the active environment.

Note 2: itsa-react-server requires CommonJS style instead of ES6 modules for actions files.

reply.reactview

reply.reactview is a very special method. It is used to route both full pages, as well as parts through Ajax. This means that you can set up a view as if it concerns a full page, without bothering how the SPA gets its parts when using client side routing.

src/routes.js:

[
...
{
method: ‘GET’,
path: '/products/product-details{productid}',
handler: function(request, reply) {
const modelConfig = {}; // optional config for the model
reply.reactview('products/product-details', modelConfig);
}
},
...
]

This example will invoke the next file:
src/views/products/product-details.jsx:

import 'assets/css/product-details.scss';import React from 'react';
import PropTypes from 'prop-types';
import Menu from 'client-modules/menu.jsx';
class ProductDetails extends React.Component {
render() {
return (
<div>
<Menu appProps={this.props.__appProps} />
<h1>{this.props.product.title}</h1>
{this.props.product.description}
</div>
);
}
}
PageInformation.propTypes = {
__appProps: PropTypes.object,
product: PropTypes.object
};
export default ProductDetails;

Note 1: The view will get “this.props” in order to render. See this article how to define the right “this.props” for your view.

Note 2: The whole page, incl. the Menu needs to be rendered by the view.

Note 3: itsa-react-server has a nice way of dealing with authentication. This will be discussed in a next article

Webpack chunks

During the built of your project, all views inside src/views are used by webpack3 to generate combined css and Component files for these views. These files are stored inside build/private/assets/css and build/view_components and will be used to generate the server side rendered pages. The Components are different from the view Components when they are requested by the SPA. These components are the full page, starting with the <html> tag and include the code for the main app.

Client side routing

To start with: there is absolutely no setup or coding needed to enable client side routing with itsa-react-server! The only thing you need, is to keep the file src/app.js, which will be transferred to the client automatically.

Yet, the next paragraphs will give you more insight in its process and features.

Single Page Application and anchor nodes

Itsa-react-server generates a Single Page Application (SPA), which means that loading subsequent relative pages will not lead into a full page refresh. Instead, it will use Ajax to load the proper css, Component and this.props of that page (view).

It can achieve this, because the server has sent a route-scheme on the first request, as part of this.props.__appProps. Internally, the client app (src/app.js) has set a delegated eventlistener on the <body> element, which will prevent default any anchor clicks that match one of the routes as specified by this scheme. What this means is this: any a-click that has a matching view will be interrupted, preventing it from loading the full page. Instead, app.js will load the view its css, Component and this.props and will render those inside its react view container.

Webpack chunks

During the built of your project, all view inside src/views are used by webpack3 to generate combined Component files for these views that can be served by a SPA request. These files are stored inside build/private/assets/js. These Components are different from the full view Components as they only specify the Component that should be rendered in the React.js container. Neither has it the code for the main app.

Full pages vs. SPA requests

When setting up the project, you don’t need to make any distinction between full page request or request made by the SPA. The same routes, views and models are being used: everything is taken care of by itsa-react-server internally.

A full page request will serve a different response than a request from the SPA: a SPA-request has specific request-headers that leads into responding only the css, Component or this.props.

In the next article, I will discuss best practices for using asynchronous models.

)
Marco Asbreuk

Written by

VP Engineering, LINEA System LLC

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade