...

/

Implementing Async Pages

Implementing Async Pages

Learn how to implement async pages in javascript applications to address data fetching problems.

Now that we know how to solve our data fetching problems, let’s implement the async pages technique in our application.

Our components tree is already structured in a way that it’s compliant with what’s expected by this technique. Our pages are the AuthorsIndex component, the Author component, and the FourOhFour component. The first two require universal data loading, so we will have to convert them into async pages.

Let’s start to update our application by extrapolating the route definitions into a src/frontend/routes.js named dedicated file.

Press + to interact
import { AuthorsIndex } from './components/pages/AuthorsIndex.js'
import { Author } from './components/pages/Author.js'
import { FourOhFour } from './components/pages/FourOhFour.js'
export const routes = [
{
path: '/',
exact: true,
component: AuthorsIndex
}, {
path: '/author/:authorId',
component: Author
},
{
path: '*',
component: FourOhFour
} ]

We want this configuration file to be the source of truth for the router configuration across the various parts of the application, so let’s refactor the frontend App component to use this file as well.

Press + to interact
// src/frontend/App.js
import react from 'react'
import htm from 'htm'
import { Switch, Route } from 'react-router-dom'
import { routes } from './routes.js'
const html = htm.bind(react.createElement)
export class App extends react.Component {
render () {
return html`<${Switch}>
${routes.map(routeConfig =>
html`<${Route}
key=${routeConfig.path}
...${routeConfig}
/>`
)}
</>`
}
}

As we can see, the only change here is that, rather than defining the various Route components inline, we build them dynamically starting from the routes configuration array. Any change in the routes.js file will be automatically reflected in the application as well.

At this point, we can update the server-side logic in the src/server.js file.

The first thing that we want to do is import a utility function from the react-router-dom package that allows us to see if a given URL matches a given React router path definition. We also need to import the routes array from the new routes.js module.

Press + to interact
// ...
import { StaticRouter, matchPath } from 'react-router-dom'
import { routes } from './frontend/routes.js'
// ...

Now, let’s update our server-side HTML template generation function to be able to embed preloaded data in our page.

Press + to interact
// ...
const template = ({ content, serverData }) => `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My library</title>
</head>
<body>
<div id="root">${content}</div>
${serverData ? `<script type="text/javascript">
window.__STATIC_CONTEXT__=${JSON.stringify(serverData)}
</script>` : ''}
<script type="text/javascript" src="/public/main.js"></script>
</body>
</html>`
// ...

As we can see, our template now accepts a new serverData named argument. If this argument is passed to the template function, it’ll render a script tag that’ll inject this data into a window.__STATIC_CONTEXT__ named global variable called.

Now, let’s get into the ...