React Hooks & Async Requests

Gary Evans
Yoyo Engineering
Published in
3 min readJun 3, 2019

At Yoyo we use React to power our core B2B product, Engage. This marketing platform enables retailers to segment their customers based on user properties, as well as past and predicted future behaviour.

Consumer Segmentation via Engage

Through Engage, retailers can target control/test campaigns and push/email comms at these customer segments. They also receive detailed reporting on campaign performance and ROI.

We have a small team to focus on Engage, but our 20% “pink sky” engineering time enables us to continuously play with new tech, and React Hooks really sparked our interest.

The initial code we created was simple and worked great, but then came the issue of writing tests. In this post we take a look at the state of our current ecosystem and consider how we implement and test components using React Hooks.

What does a component with Hooks look like?

Many components we create rely on making API calls, handling errors, and rendering successful responses. We make use the render prop pattern so we can write our asynchronous logic once and reuse across presentational components. A component that meets these requirements is shown below:

Here we make use of useState to maintain three values:

  • isLoading - are we currently fetching data?
  • hasError - was something bad with the request?
  • response - a successful response body or error

We are also using useEffect to perform the asynchronous fetch to our API. This will initially reset to a default state, attempt to fetch data, handle any errors, and finally set loading to false. This will only fire when mounted for the first time and anytime our url prop changes.

The nature of asynchronous events means we cannot guarantee requests are fulfilled in the same order we execute them. If our promise resolves after our component has unmounted it will lead to a memory leak. Before we would implement componentWillUnmount to contain some clean up logic but with Hooks we simply return a function which will be executed between effect runs. We can piggy back on this so we only update state with the most recent request — useful if long running requests resolve out of order.

How do we test this?

We currently use enzyme to render components in our unit tests, alongside helper libraries like chai for assertions and sinon for mocking. Some example tests for this component:

We stub the API fetch logic which allows us to test good and bad results. It’s important to run assertions once the stub return promise has resolved/rejected due to the asynchronous nature of useEffect in our example.

…and how do we use this?

We now have a reusable component to fetch results from any API. Using the render prop pattern we can create a presentational component which is able to display a loading state, error state, or a successful response:

So far React Hooks have been a great addition in our team. We have found less class lifecycle implementations has led to fewer lines of code and more readable components.

Hopefully this provides a quick insight to React Hooks, how we are using them at Yoyo, and spurs you on to try them too.

--

--