Migrating to Single Page Application

Jessie Zhu
Jul 30, 2017 · 4 min read

Recently our team built a mobile H5 web app for our fitness platform. The stack we adopt is React, Redux and Webpack. We didn’t make it a Single-Page Application(below we will refer it as SPA) first because the development cycle is too short for us to study Single-Page Application and solve the unknown problems we will probably meet. But as the application grows, we feel it necessary to transform it to SPA. I took this assignment and in this passage I would like to share the challenges I met in migrating my web app to SPA and how I solve it.

First, I would like to share the the pros and cons of SPA.

Pros of the SPA

1. SPA is fast, as most resources (HTML+CSS+Scripts) are only loaded once throughout the lifespan of application. Only data is transmitted back and forth.

2. Easier state tracking — no need to use cookies, local storage, session storage etc. to remember state between 2 page loads. (We use Redux as the state management, so this advantage really stands out)

3. Boiler plate content that is on every page (header, footer, logo, copyright banner, etc.) only loads once per typical browser session.

Cons of the SPA

1. SEO
2. It is slow to download because heavy client frameworks are required to be loaded to the client.
3. Memory leak in JavaScript can even cause powerful system to slow down.


Then let’s see how I gradually migrate my MPA(multi-page application) to SPA.

I chose React Router for routing and Redux for state management.

Step1 Multi Entries to Only One Entry
We use webpack for bundling. And there used to be multi pages so there is multi entries. Now I only created an “index.jsx” in entry file and left the original pages to be imported as components in the index file. The file structure looks like:

  - entry
index.jsx
- pages
1.jsx
2.jsx
3.jsx

And to keep the original url, I need configure the “webpack.config.js” to redirect all the urls to index.html and let the index file to distribute url address.

It works like that:



devServer:{
historyApiFallback:{
disableDotRule: true,
rewrites: [
{from: ‘’, to: ‘/index.html’},
]
}
}

Step2 Multi body elements to full screen div

We used to attach background color to the body element. However, for SPA there is only one body element. So we need to make the component div full screen and it should be able to stretch to the whole content height. Each component has a basic class name “page”, and has its own name “page-name”.
To make the div full screen:

 html, body{
height:100%
}

.page{
min-height: 100%;
}

Step3 Redux for state management

As the requirements for JavaScript single-page applications have become increasingly complicated, our code must manage more state than ever before. Redux is created under such circumstance to make mutations predictable.

Redux stores the state of the whole application in an object tree within a single store. Therefore, we can cache server responses and locally created data that can be shared in different components.

In the action file, I created different actions to talk to different API for different data, and save the response data in store.

Every time I enter a component, I check if the pageData has exists in ComponentWillMount(). If yes, we return and don’t talk to API. If no, talk to the API to load the latest data and save it to store. In this process, it’s easy to realize data cache and when we switch different pages, the page can stay in the previous state without refreshing again and again.
It’s really a huge progress which really excites me.

Step 4 React Router path
Speaking of React Router, I would like to mention that since React Router has already migrated to 4.x. Some APIs are different from before. For example, we need to import {BrowserRouter, Route, Link} from ‘react-router-dom’ not ‘react-router’.

And react-router doesn’t support param beginning with “?”. It won’t trigger component re-build if the param after “?” changes. But we have to be compatible with the previous urls. So we need to compare the current id with the previous id and manually trigger the re-build.

Step 5 Unbind Events to avoid Memory Leak
React provides a ComponentWillUnmout() method to trigger method before a component is unmounted, but we seldom use it in MPA. However, it’s quite important to unbind events in SPA or it will cause memory leak.

So far, things went well and I really enjoy the instant load of SPA. At the same time, we still have some issues to be settled:
1. Improve the initial page loads
2. SEO
3. Test the performance of SPA

To be continued!

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