Fetching API Data with React Hooks, HOC or Render Prop
Tags: javascript, react, hooks, hoc
Published: 2019-06-23 20:24:44

Let’s look at the implementation of data fetching using a new friend React Hooks along with good old friends: Render Prop and HOC (Higher Order Component). And find out if it’s true — ‘Old friends and old wine are the best’.

![](https://thepracticaldev.s3.amazonaws.com/i/apfftof2d3jup9hv9f1o.jpg)

As life goes on changes, React changes for the better. In January 2019 React Hooks were added in React 16.8.0. Since then we can use local state and run side effects in functional components. Hooray! Nobody believed that it’s possible but everybody was dreaming about it. Before reading this article please make sure that you have read documentation about React Hooks.

React Hooks give an opportunity to stop using HOC and Render Prop in most of the cases. Since we have a lot of complaints about them:

HOC + Render Prop:

1. “Wrapper hell” makes it complicated to read code and debug.

HOC:

1. Problems with type annotation (flow, TypeScript).
2. Sometimes it’s hard to determine an owner of component props.
3. Props “naming collision”. You can override prop values with the same key.
4. HOC composition is not always evident. E.g. you need “Authorisation HOC” wrapped component after “Profile Fetcher HOC”. It means “Authorisation HOC” should be executed first.

Render Prop:

1. Render Prop usually doesn’t render any HTML elements, is used alongside JSX.

2. Useless “git diff” due to line indenting for the whole JSX inside Render Prop. It looks you changed a lot, but actually just added only one Render Prop.

Let’s take a deeper dive and look at the example that demonstrates what is better — React Hooks or Render Prop. We will use Render Prop, its implementation is similar to HOC and less verbose. We will write a utility that fetches data from API. I’m pretty sure you’ve already coded this dozen times, so let’s see if we can write it better and more elegant.

We’ll use the popular library “axios”. With the simplest scenario we should handle the following statuses and actions:

- fetching process (isFetching)
- success response (responseData)
- failed response (error)
- cancel request and send the new one if the url is changed
- cancel request for an unmounted component

### 1. Simple scenario

Let’s write initial state and a reducer function, which modifies state depending on fetched result: success or error.

>Note: The term “Reducer” came from functional programming. A lot of JS developers learned it from Redux. It is a function that accepts the current state and an action and returns the new state.

{% gist https://gist.github.com/KateKate/85152a23b251cf4f52548d28ca175134 file=reducer1.js %}

We’ll use this function in both approaches.

{% gist https://gist.github.com/KateKate/02afe34278c5c97277d4953cb500b773 file=RenderProp1.js %}

{% gist https://gist.github.com/KateKate/fbb08ec95f116c0fb90b3757af8ec0c1
file=useRequest1.js %}

We fetch data by calling axios.get() with url. Then we handle success and error statuses by dispatching an action to update the state. Don’t forget to cancel the request if the url has changed or the component has been unmounted. It’s simple, but we could write it differently. Let’s highlight the pros of these two approaches:

Hooks:

1. Less code.
2. Side-effect (data fetching) is easier to read, since it’s all in one place and not spread over the lifecycle methods.
3. Request cancellation goes after request immediately.
4. Simple code to trigger a side effect in response to prop changes.

Render Prop:

1. It’s obvious in which lifecycle phase our code is executed.

It’s a fact that Hooks allow to write less code. So the effectiveness of you as a developer is growing. But you have to understand a new paradigm.

Everything is clear if you have lifecycle methods. We send initial request when a component is mounted (componentDidMount). Then refetch data and cancel the previous request if the props have changed (componentDidUpdate). And don’t forget to cancel the request if the component is unmounted (componentWillUnmount).

But now we perform all these side effects in the render. React team has taught us that it’s wrong. Hmm, it’s not in the render actually, but inside the useEffect hook, which will execute something asynchronously after each commit phase and DOM paint.

We don’t need to fetch data after every render, only after the initial one and whenever the url changes. That’s why we pass the url as the second argument in useEffect.

>**A new paradigm.** To understand Hooks we need to learn new things. The most important one is the difference between the two phases: render and commit. In the render phase React figures out what changes should be applied to the DOM by comparing the results of the previous and the current render. In the commit phase React applies these changes to the DOM. During the commit phase componentDidMount and componentDidUpdate are called synchronously before the browser updates the screen. You might block the browser if you perform some large synchronous operations. Unlike these methods, the function passed to useEffect will be called asynchronously and will not block the browser from painting.

Another nice feature — useEffect will clean up after the previous effect and after a component is unmounted. Thanks to Rx that inspires the React team to take this approach.

Our utility usage is more convenient with Hooks.

{% gist https://gist.github.com/KateKate/62079cb92780eec73a7bc128efbd517a
file=AvatarRenderProp1.js %}

{% gist https://gist.github.com/KateKate/c742ecf020f55af0b7b0bb529b211789
file=AvatarWithHook1.js %}

Render Prop cons:

1. It is not clear whether any markup is added or it’s just logic.
2. If you want to use Render Prop state inside lifecycle methods you will have to create an extra class component.

Let’s add a new feature — trigger a new request by a user action. We will make a button that if clicked fetches a new avatar of your favourite developer.

### 2. Update data by user action

We will add a button that sends a request with a new username. The simplest solution is to store username in the component state and use it instead of passing it from props directly. . But in that case we will have to “copy-paste” this code for every component which need the same logic. To avoid “copy-pasting” let’s carry out this functionality into our utility.

We’ll use it in the following way:

{% gist https://gist.github.com/KateKate/27c3cfed167b68f99e0170af9c70bfdf
file=Avatar2.js %}

Let’s code. Below are only the changes compared with the previous version.

{% gist https://gist.github.com/KateKate/c4f74d67630651a2f29ba1e216628add
file=reducer2.js %}

{% gist https://gist.github.com/KateKate/d302450756ebd519d23d1f8fa2ebbd69
file=RenderProp2.js %}

{% gist https://gist.github.com/KateKate/5360d28e33c5f2ecd7019bc831a53dff
file=useRequest2.js %}

If you look closely at the code you can notice:

1. url is stored inside our utility;
2. defaultUrl lets us identify that the url update is caused by the props. We need to keep track of the current props.url, otherwise a new request will not be sent;
3. a new function ‘update’ has appeared. We return it to the component to send a new request by clicking the button.

With Render Prop we need getDerivedStateFromProps to update the local state in case of props.url changes. But with Hooks you can change the state in the render, there are no new abstractions. Finally we can modify the component state in the render, hooray!!!

Hooks require the only complication — the “update” function must be memoized so it’s not re-created on every render. In Render Prop “update” is simply a class method.

### 3. API polling

Now we are going to add another popular feature. Sometimes you constantly have to poll your API. For example, your favourite developer might have changed the avatar so you should be the first one to know. We need a polling parameter — interval.

Usage:

{% gist https://gist.github.com/KateKate/2d6a068bc81724576ee6378b4b2aaad2
file=AvatarRenderProp3.js %}

{% gist https://gist.github.com/KateKate/00cdfbfc9b9e9980625aeeb80bd07b5f
file=AvatarWithHook3.js %}

Implementation:

{% gist https://gist.github.com/KateKate/f68146457758a8843fa513b66d900730
file=reducer3.js %}

{% gist https://gist.github.com/KateKate/79ac4f97172a465c7f76b50d55ed5bb0
file=RenderProp3.js %}

{% gist https://gist.github.com/KateKate/c123f9a94fc462791c00d2bb80ef2734
file=useRequest3.js %}

We created a new action type “poll” that increments “state.requestId” by one. If data is not being fetched we dispatch “poll” with setTimeout once the interval expires. Then we should send a new request when “state.requestId” changes.

With Hooks:

1. perform setTimeout in a new useEffect,
2. pass the new argument “requestId” in the old useEffect with data fetching.

With Render Prop:

1. perform setTimeout in componentDidUpdate,
2. compare previous to new “requestId” and “isFetching”,
3. clear “timeoutId” in two places,
4. add “timeoutId” class property.

With Hooks we can express the same things cleaner and shorter than we used to.

### 4. What’s next?

We can continue to expand the functionality of the utility: different configurations of query parameters, data caching, response and error handlers, data refresh with the same parameters — these are regular operations in any large web application. In our project we extracted all these features in a separate component. Yes, a component! It was Render Prop. Since Hooks have appeared we converted the component into a hook (useAxiosRequest) and we even found some bugs that we didn’t notice before! You can try it [here.](https://github.com/Turanchoks/use-axios-request)

*Contributions are always welcome! 
https://github.com/Turanchoks/use-axios-request*