Kumar Harsh Technical writer and software developer based in India.

How and why to use React Frontload

6 min read 1912

React Frontload and React logos over a background of a field.

Web apps are focused on two primary activities: loading data and displaying it effectively. While React does a great job of displaying data with the help of native CSS, CSS in JS, and other styling alternatives, it falls short when it comes to the loading part.

A combination of fetching with proper lifecycle events might be a good solution for a complete client-side application, but when things get on the server, it’s not enough. This is where a third-party library known as React Frontload comes in. React Frontload is an effective tool for solving the issue of cross-environment data fetching and has a seamless interface that allows you to load your data inline.

Is that all? Let’s find out!

React Frontload logo.

What is React Frontload?

React Frontload is a library for React-based applications that helps to fetch data inline in both server and client environments. It offers several features that make it super simple to integrate and use. It offers a Hook for loading data, which returns the data in a stateful object, as well as a frontloadMeta object for keeping track of the status of the network request.

An important point to focus on here is that the latest version of Frontload comes with an out-of-the-box state management solution, so you as a developer do not need to worry about manually handing over data to a state container such as Redux or MobX.

With over 6k weekly downloads via npm, React Frontload has started to attract attention due to its simple set-up and developer-friendly interface. Before we dive into how to get it running, let’s take a look at the original problem in detail and how Frontload tackles it.

What problem does it solve?

As mentioned earlier, React does not offer an out-of-the-box solution to handle data fetching. The fetch API in JavaScript is capable enough of hitting external API endpoints and receiving data. But when it comes to React applications, a lot more has to be done. Once data is received, the React DOM needs to be informed about the result of the request.

If the request fails, the scenario has to be properly handled. And by the time you figure out a working solution for these cases, server-side rendered applications kick in, rendering your fetch + useEffect solution pointless.

Server-side rendering has its issues. While the asynchronous way of fetching data in parallel with rendering UI has been a great fit with developers, server-side rendering forces users to wait before all API calls are done and all data has loaded before rendering the layout and sending it down to the browser client.

We made a custom demo for .
No really. Click here to check it out.

This is why the conventional methods of asynchronously fetching data inside of components becomes irrelevant.

One might argue that a good way to solve this is to load data globally in server-side rendered apps and pass it down to various components. This also works on the client-side, as the root component can still handle fetching data and pass it down to its children via props.

But this is not a practical solution. This approach can prove to be effective in constructs like a search results page or a user profile page, but it increases complexity unnecessarily in cases such as a user’s feed or social media post.

React Frontload can help to solve this issue. The library offers a component-centric approach to implementing data fetching with in-built compatibility with SSR apps as well. This means that you do not need to implement different solutions for the two scenarios, and you are not forced to compromise on your application’s architecture either.

How does it work?

React Frontload builds on the component-specific data fetching method and adapts server-side rendering of the application to handle synchronous requests. This means that you can access the Frontload API via a React Hook and still get it working in SSR since your web server is instructed to work asynchronously just like a standard React client.

React Frontload helps your server load data asynchronously and renders the page. It returns data for the client-side hydration at the same time. All you need to do is add a single line of code that hydrates the data into the client. You’ll understand this better once we dig into the setup of the library.

React Frontload uses a reactFrontloadServer call to render client-side code from the React source, which internally looks for the useFrontload Hooks. Whenever such a Hook is encountered, its promise is collected. Once all promises are collected, they are awaited and their data is injected into the corresponding components.

Once done, the reactFrontLoadServer call runs through the source again looking for any new useFrontload calls that might have originated from the previous round of promise collections. If any new calls are found, the process is repeated with them. If no new calls are encountered, the render is marked as final and sent to the client.

Getting started with React Frontload

Initial setup

Before you can use React Frontload, there a few configurational changes that you’ll need to make.

Here are the things you need to do:

Wrap your app with the React Frontload provider

import { FrontloadProvider } from 'react-frontload'

const App = ({ frontloadState }) => (
  <FrontloadProvider initialState={frontloadState}>
    <Content>...</Content>
  </FrontloadProvider>
)

If you have an SSR app, wrap your existing synchronous server render code with reactFrontloadServerRender

reactFrontloadServerRender works similarly to how React server rendering works. All it adds is the asynchronous loading part as explained above.

import { renderToString } from 'react-dom/server'
import { createFrontloadState, frontloadServerRender } from 'react-frontload'
import apiClient from './api_client'

app.get('*', async (req, res) => {
  ...

  // create a new state object for each render
  // this will eventually be passed to the FrontloadProvider in <App>
  const frontloadState = createFrontloadState.server({

  // apiClient is a custom implementation of an API handler, that can make HTTP calls, DB operations etc 
    context: { api: apiClient}
  })

  try {
    // frontloadServerRender is first used to fetch data instead of the generic, straightforward renderToString
    const { rendered, data } = await frontloadServerRender({
      frontloadState,
      render: () => renderToString(<App frontloadState={frontloadState} />)
    })

    res.send(`
      <html>
        ...
        <!-- server rendered markup -->
        ${rendered}

        <!-- loaded data hydration on client -->
        <script>window._frontloadData=${toSanitizedJSON(data)}</script>
        ...
      </html>
    `)
  } catch (err) {
    ...
  }
})

As is evident, frontloadServerRender returns data as well as the rendered markup. The markup is then sent to the client as-is, while the data is marked to be hydrated.

This is done to ensure that the data associated with the initial view of the component is not reloaded upon client-side rendering, and the prefetched data is injected into the components via initialState.

Handle the hydration operation on the client-side

The final step in the process for SSR-ready apps is to handle the initial data hydration on the client end.

This can be done with the following code:

import apiClient from './api_client'

const frontloadState = createFrontloadState.client({
  // use client's implementation of api to load data.
  context: { api: apiClient },

  // hydrate state from SSR
  serverRenderedData: window._frontloadData
})
...
ReactDOM.hydrate(<App frontloadState={frontloadState} />, ...)

That’s it for the initial setup. Now, let’s take a look at how to use this when fetching data inside components.

How to use React Frontload

Here’s a sample component that uses React Frontload to load data from the API asynchronously and handles all possible results of the HTTP request as well:

const Component = () => {
  const { data, frontloadMeta } = useFrontload('some-component', async ({ api }) => ({
    something: await api.fetchSomething()
  }))

  if (frontloadMeta.pending) return <div>loading</div>
  if (frontloadMeta.error)   return <div>error</div>

  return <div>{data.something}</div>
}

In the above example, the useFrontload Hook has been used to get the data as well as a meta object. The data object contains the response from the API call and is defined as an object containing a property, something, which is fetched by an API client.

Note that this API client (api) is the same client you would pass in step 3 of the initial setup. A typical API client would expose methods that can be used to perform remote server-based operations and return results and/or data.

While the API client is busy loading data, the meta object has the pending property set to true, which in the above case is used to show a loading UI to the user. Also, errors can be handled easily by checking for the meta.error property.

useFrontload also exposes some other properties, which can come in handy in various situations. For instance, a setData method is exposed along with the data variable that allows you to update the data object later if you’re planning to fetch more data based on user activity.

This is how it can be implemented:

const Component = () => {
  // setData is a tiny reducer that can update the data object on the fly.
  const { data, setData, frontloadMeta } = useFrontload('some-component', async ({ api }) => ({
    something: await api.fetchSomething()
  }))

  if (frontloadMeta.pending) return <div>loading</div>
  if (frontloadMeta.error)   return <div>error</div>

  const updateSomething = async () => {
    try {
      const updatedSomething = await updateSomething('new value') // API call to update the data
      setData(data => ({ ...data, something: updatedSomething })) // update data in state
    } catch {
      ...
    }
  }

  return (
    <>
      <div>{data.something}</div>
      <button onClick={updateSomething}>Update!</button>
    <>
  )

Seems simple, doesn’t it? Let’s kick things up a notch.

Here are two API calls in one component using React Frontload:

const Component = () => {
  const { data, frontloadMeta } = useFrontload('some-component', async ({ api }) => ({
    something: await api.fetchSomething(),
    someMoreThings: await api.fetchSomeMoreThings() // just added this as an additional API call
  }))

  if (frontloadMeta.pending) return <div>Loading!</div>
  if (frontloadMeta.error)   return <div>Something went wrong</div>

  return <div>{data.something} and {data.someMoreThings}</div> 
}

There’s one little thing that we’ve missed out on. If you take a look at the performance of the useFrontload call as we’re using it in the above example, you’ll notice it is fairly slow.

Apparently, this is because it is awaiting the promises one by one. This can be improved by loading all of them in parallel.

Here’s the fix for that in the same snippet:

const Component = () => {
  const { data, frontloadMeta } = useFrontload('some-component', async ({ api }) => {
    const [something, someMoreThings] = await Promise.all([
    api.fetchSomething(),
    api.fetchSomeMoreThings()
  ])

  return { something, someMoreThings }
  })

  if (frontloadMeta.pending) return <div>Loading!</div>
  if (frontloadMeta.error)   return <div>Something went wrong</div>

  return <div>{data.something} and {data.someMoreThings}</div> 
}

That’s it. You have blazing-fast data fetching bundled with a state container with its own little reducer to fetch, render, and update data as swiftly as possible.

Conclusion

React Frontload is a handy tool when it comes to handling remote data efficiently, and it only gets better when you consider all of its features. As a React developer, if you’re aiming to scale reliable apps quickly, you’ve got to check out the library at least once. I’m pretty sure it will suit your needs and make your development process a lot faster.

This project is under active development, and a lot of the hottest features have been introduced in the latest versions, so it’s safe to say that it will only get better with time.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Kumar Harsh Technical writer and software developer based in India.

Leave a Reply