Implementing Async Pages
Learn how to implement async pages in javascript applications to address data fetching problems.
We'll cover the following...
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.
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.
// src/frontend/App.jsimport 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.
// ...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.
// ...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 ...