Using a Headless CMS and React to Build Single Page Apps - Part 1

This is a two part series blog post, here is the second part.

Headless What?

A headless CMS system allows users to control all the content, with strict separation from the display or front-end layers. Allows content creators to focus on what they do best: create high-quality content. A headless CMS architecture empowers marketers and developers to work together to deliver engaging customer experiences. One notable use case for headless CMSs today is creating Single Page Applications (SPA). SPAs deliver more dynamic user experiences, similar to what you might expect from a native mobile application or desktop application, making them very popular with today's customers.

In this piece, I'll walk you through how to use a headless CMS and React to build a SPA, using the headless capabilities of dotCMS, an enterprise, open-source Java CMS. If you want to jump right into the code, here is the repo: https://github.com/fmontes/dotcms-page

Creating Pages and Layouts From dotCMS's APIs

Almost all headless CMSs on the market have APIs that can be used to distribute various content types to any device or touchpoint; however, what I like about dotCMS is that you can create pages templates and layouts via its API. This is dotCMS's Layout-as-a-Service, which opens the door for:

Layout-as-a-Service gives dotCMS an edge over other headless CMSs on the market and is something worth looking into; however, for this tutorial, I'll only be retrieving pages that have already been created.

Before We Get Started, You'll Need

  1. Headless CMS (I'll be using dotCMS for this tutorial).
  2. Node.js and npm.
  3. Some React.js knowledge (I'll walk you through the whole process).

Let's Build a Single Page Application

Creating a React app is super easy now, thanks to Facebook's CLI tool, called create-react-app. It lets you create a React app without having to worry about all the hassle of servers, build, or testing.

First, get your Node.js installed and npm fired up in a terminal, then run:

npx create-react-app dotcms-page
cd dotcms-page
npm start

npx will run the create-react-app to create a React app called dotcms-page. By default, npx will check whether <command> exists in $PATH or in the local project binaries, and execute. If <command> is not found, it will be installed prior to execution.

With cd, we'll browse into the new folder dotcms-page.

And by running npm start inside the app folder, it will run the app in development mode. Open http://localhost:3000 to view it in the browser:

Create React App First View

dotCMS Page Structure

As you can see in the diagram below, the dotCMS's page structure is just a nested group of elements: Rows > Columns > Containers > Content, where content can be news, events, blog posts, etc.

CMS structure

The Page Object

The response for the Page API in dotCMS will give all the information on a page, which includes:

To build a page with React, we'll consider the layout, containers, and the page contentlets.

Layout

This object tells us how to render the page, how many rows and columns, what size, offset, etc. Once we have all the information of the rows, columns, containers, and sidebar, we'll use that information to create React components and build our page.

Please note that this object doesn't contain the content of the page. We'll add that in another section of the page object.

Let's take a look at this example of a Layout object:

interface Layout {
    pageWidth: any;
    width: any;
    layout: any;
    title: string;
    header: boolean;
    footer: boolean;
    body: {
        rows: [
            {
                identifier: number;
                value: any;
                id: any;
                columns: [
                    {
                        preview: boolean;
                        containers: [
                            {
                                identifier: string;
                                uuid: string;
                            }
                        ];
                        widthPercent: number;
                        width: number;
                        leftOffset: number;
                        left: number;
                    }
                ];
            }
        ];
    };
    sidebar: {
        preview: boolean;
        containers: [
            {
                identifier: string;
                uuid: string;
            }
        ];
        location: string;
        widthPercent: number;
        width: string;
    };
}

Now, let's go over the properties we'll be using to create our page using React components:

Containers

Another property we have to consider is the list of containers --- here we're going to find all the contentlets in the page and we will match them with the identifiers in the Layout to render in the appropriate columns in the page. The containers object use an entity format which looks like this:

interface Containers {
    [identifier: string]: {
        container: {
            identifier: string;
            title: string;
            friendlyName: string;
        };
        contentlets: {
            [uuid: string]: [
                {
                    owner: string;
                    identifier: string;
                    hostName: string;
                    modDate: number;
                    languageId: number;
                    body: string;
                    title: string;
                    url: string;
                    baseType: string;
                    inode: string;
                    titleImage: string;
                    modUserName: string;
                    archived: boolean;
                    folder: string;
                    hasTitleImage: boolean;
                    sortOrder: number;
                    modUser: string;
                    host: string;
                    working: boolean;
                    locked: boolean;
                    stInode: string;
                    contentType: string;
                    live: boolean;
                }
            ];
        };
    };
}

In this object, we'll find an entity for each identifier linked to any part of the page, and with the containers identifier in the Layout object, either in the body or in the sidebar, it will find the exact match for the contentlets to render the content in the React component.

contentles.uuid-[N]: contains the contentlets information and will vary depending on the content type fields. We'll use those fields to render the contentlets in the page.

Copyright © 2024. Design and code by myself with Next.js. Fork it and create yours