Setting up Modular Express routing, React Router and basic components.

This post is the Lesson 2 of React online course from JS Mega Tools. You can get the code for the previous lesson at the following address: https://github.com/jsmegatools/React-online-course  Once you’ve cloned the repository you can go into Lesson-1 folder and edit files the way its done in this tutorial.

In the previous lesson we set up a basic React and Node.js project. In this lesson we are going to continue to work on our application and set up modular routing with Express Router on the server and routing for React with React Router on the client. We are also going to take a look at some basic React components.

Setting up React routes.

Our travel accommodation app is going to feature 2 main routes: a main area, which is what the most users of the app are going to use and an admin area. There also going to be some additional routes like login and registration routes. To define the routes we are going to use React Router.

First we need to install React-Router. Run this in the directory where React code is located, in our case it is react-ui directory:

npm install react-router-dom —save

Now we are ready to add routes for our client side application. We are going to add routes inside App.js file, that was created for us by create-react-app.

App.js holds a root component of our application. React components represent units of functionality in React. You compose your UI with components. Components can be defined in various ways. One of them is through ES6 classes. That is what we are going to use the most in our code.

A component should contain a render method that returns a UI representation of the component. The most used form of UI representation for components is JSX. It is like HTML, but you can use custom elements and javascript in it. Custom elements represent react components. Everyone can write their own components and use them in an application. One can use components from third party libraries from npm too. Usually there is one component per file and it gets exported from that file.

App.js was created for us with create-react-app in lesson 1, you already had a chance to take a look at it, now we are going to modify it.

First we need to add imports for React Router components like this:

import {
  BrowserRouter as Router,
  Route
} from 'react-router-dom';

Then we should replace the return value of render method of the App component with the following JSX:

<Router>
  <div>
    <Route exact path="/" component={MainArea}/>
    <Route exact path="/admin" component={AdminArea}/>
  </div>
</Router>

Components have props. In JSX props are represented by attributes on elements. Props are a way to pass values to a component from an outer environment. For example here we have exact, path and component props passed to Route components.

The JSX above is how you set up routes with React Router 4. The Router is an alias we picked for Browser router which is what is used to create a router for a web environment. If you wanted to develop an app for React Native for example, you would use a NativeRouter from react-router-native, and if you wanted to use routing in server side rendering you would use StaticRouter from react-router.

Now, you can’t just put several routes as children of the Router component, you have to wrap them in an element or a component. You can use a div element for that or, if several routes match some path and you want just one component to be rendered, you can use Switch component from react-router-dom. We will stick to div for now.

Every Route has a path prop that matches a url (if they didn’t a they would match any url). A Route may have a prop called exact, which causes a Route to match only the exact path and not any paths starting with the value of path prop. We are going to use exact for every route, later we can adjust it when adding new features.

We are also using component prop, it is used to tell a Route component what component we should render at a specified path.

We are going to have two routes: MainArea and AdminArea. MainArea represents the main part of the app, that all users going to be able to access. AdminArea component represents the admin. We need to create imports for them near the top of the file:

import MainArea from ‘./components/MainArea/MainArea';
import AdminArea from ‘./components/AdminArea/AdminArea';

We are importing these components from `components` folder. This folder is going to contain presentational components of our React application (They are responsible for UI). The app is also going to have container components (They handle passing data to and from Redux store), we’ll talk more about those components later.

Since we are importing from the `components` folder, let’s actually create this folder and the imported components. We are using components’ names as file names. While that makes imports look a bit verbose, it helps finding components’ files through IDE tabs while editing and through browser developer tools tabs while debugging.

We can put the following code into each file to check the basic functionality in the browser. Make sure adjust the names of classes and html contents of a component to match the filename of the component:

import React, { Component } from 'react';

class MainArea extends Component {
  render() {
    return (
      <div>Hello MainArea!</div>
    );
  }
}

export default MainArea;

Right now if you launched the app it would have two available pages that show their respective content. This is how React Router works in a nutshell. Later we will use more of its functionality, but for now this simple setup is more than enough.

Setting up modular routing with Express router.

Let’s leave our happy React land and venture into a happy, but still unexplored server side. Time for setting up server side routing. We are going to utilize a scalable solution, based on Express router. All our routes are going to be located in routes folder. Inside that folder there will be a separation by the kind of routes. After creating a routes folder we are going to create api folder for api routes. Then inside the api folder let’s create index.js file with the following contents:

const express = require('express');

const apiRouter = express.Router();

const getLocations = (req, res) => {
  res.sendFile(process.cwd() + '/data/locations.json');
}

apiRouter.get('/locations', getLocations);

module.exports = apiRouter;

We are setting up an Express router with express.Router method. Express router acts like a mini express application, because is it provides the essential functionality that express itself provides but limited to the path it is mounted on. This allows us to distribute routing and route handling among several routers and limit the scope of the router responsibility based on the path it is mounted on.

After we have put the newly initialized router into apiRouter constant, we define a handler, that allows us to get a list of locations where travel accommodations are located. This kind of data usually comes from a database, after some manipulations have been applied to it, but for now we are going to use a file as a storage medium, because at this point we don’t have a lot of data to work with. Let’s create a data directory in the root directory of our project. In the data directory we are going to store files containing JSON data which is not too complex as to require database storage.

The data in locations.json file has the following structure:

[
  {
    "id": 1,
    "name": "London",
    "image": "london.jpg"
  },
…
]

So far our root directory looks like this:

data
node_modules
package-lock.json
package.json
react-ui
routes
server.js

In the handler we send the locations.json file from data directory back to the client. Finally we pass the handler to the locations route with the following line:

apiRouter.get('/locations', getLocations);

Then we export the router.

We have just created the api router responsible for the api. It can handle various api requests and direct them to sub-routers and add api specific middleware.

To make everything work we need to include the api router into the application. For that we need to first import it in server.js file at the root folder of our application:

const apiRoutes = require('./routes/api');

Then we need to add the following code to the server.js file:

app.use('/api', apiRoutes);

Make sure that you put them before the following code:

app.get('*', function(request, response) {
  response.sendFile(path.resolve(__dirname, './react-ui/build', 'index.html'));
});

This is important because in Express routes are matched to a url in order of their definition in a source code, and because we have a route with a star (a route that matches all paths). That route sends a response to a client, and that means every matching route after that will be skipped. Because the star route matches every path, it will match /api path also and, if it is defined first, it will be executed first, and our api specific route will be skipped.

Now its time to check how everything works. Let’s set up data fetching on the front end. First we need to install a http library to make http requests to the server:

npm install --save cross-fetch

Then we should replace the contents of components/MainArea/MainArea.js with the following:

import React, { Component } from 'react';
import fetch from 'cross-fetch';

class MainArea extends Component {
  constructor(props) {
    super(props);
    this.state = {
      locations: []
    };
  }

  componentDidMount() {
    fetch('/api/locations').then(res => res.json())
      .then(locations => this.setState({ locations }));
  }

  render() {
    return (
      <div className="home-page-container">
        {
          this.state.locations.map(location =>
            <li key={location.id}>
              <img src={location.image} alt={location.name} />
              {location.name}
            </li>)
        }
      </div>
    );
  }
}

export default MainArea;

That is how React component with a state looks. It is a ES6 class with a constructor, where the state is defined. Class syntax requires us to call `super` method, before referencing `this` keyword. We call it with props. These are the same props that we encountered earlier when looking at elements that represent components in JSX. This time we look at props from a component’s perspective, rather than from outer environment perspective. Next we define the component’s state. It has `locations` property, that is going to hold a list of locations, by which a user can search for accommodations.

Next, we have a componentDidMount lifecycle method, that is called after a component has rendered. It is a recommended method to fetch data, needed for initial component render. Because a component will render at least once before the needed data has been received, it is recommended to show some kind of a loader animation to a user. We will handle this in the following lesson. Here we make a get request with fetch library to the api endpoint we have just defined (/api/locations). fetch returns a promise, then we get another promise from response, that resolves to a json array of locations.

Then we use a setState component method of React, which updates a component’s state and triggers a component’s rerender. In render method we iterate over locations array from the state with map function to build a list of locations.

One important thing for create-react-app apps running in development and accessing data. We are running a webpack development server and an express server on different ports. When a React app requests data from a front-end server it will be a Cross-Origin Resource Sharing, and the browser will prevent this request. To get around this, we need to tell webpack devserver to proxy requests that don’t match anything to the Express server. This is done with `proxy` property in react-ui directory’s package.json file:

"proxy": "http://localhost:5000"

Where 5000 is a port number our Express server is running on.

This is it for the lesson 2. In this lesson we have learned how to set up routing for React and Express, we have also learned the basic structure of React components. Source code for this lesson can be found at the following address.

https://github.com/jsmegatools/React-online-course