Getting Hooked on React

Chris Sullivan
The Startup
Published in
4 min readJul 4, 2019

React has made a large statement with their 16.8 release and the inclusion of hooks. Not only does it signal a paradigm shift away from React classes, but it offers a more streamlined way of creating components. It is, however, not without a learning curve. Enthusiastic adopters can take advantage of hooks to create; higher order components (HOC), reusable utilities, or contextual providers in a streamlined manner.

Utility

If you have experimented with hooks, you will have noticed that they can be declared in external functions yet used within the body of a Functional Component. This is because of hooks chaining mechanism. Here is an example of external hook usage.

The example above is a wrapper around useState which will persist the data to localStorage. If we declare this in a utilities directory we can then re-use this code anywhere we want to persist data. A couple use-cases for this would be user tokens, current page, or form data.

Contextual Providers

If we continue our use of Functional Components and take advantage of React hooks we can greatly simplify the code needed for Providers and Consumers. Below we have an example of a contextual Theme.

The Theme makes use of the usePersistState utility we created in the first example to store our curent theme to localStorage. This illustrates how easily external hooks can be pulled in and re-used. Again, we greatly simplify the higher order component, withTheme by using the hook useContext . The HOC boils down to a curried function, that injects contextual props into the Component, we don’t even need to create a WrappedComponent!

Re-use: useAsync

Since we are working in web, a common task for developers is to make asynchronous calls. I wrote a library called @sullivan/use-async to handle these common occurrences, in the next part, I’ll break down how it works, but here is a snippet for useAsync.

As you can see, internally it calls the hook useReducer (Reducers).

  1. Our reducer asyncReducer is a slim wrapper around an array config.
  2. The type value we use for the dispatched actions is a number, that performs a 1–1 lookup on the array and then invokes the function at that index.
  3. We wrap the dispatch method of the reducer so that when a user of the utility calls dispatch we update our states accordingly.
  4. Lastly, we return the current state and our wrapped dispatch method.

So why is this external hook so powerful, and how can we leverage it in our apps? Below is an example illustrating useAsync in a Functional Component.

Consuming the useAsync utility can be seen above. When dispatch is called, our reducer state is then propagated up to our Example Component. It is powerful for the following reasons.

  1. No more bloated async class methods
  2. It exposes our asynchronous state within a synchronous function
  3. Automatically updates for us
  4. Provides a built-in loading flag

But wait, what about dynamic parameters? Wouldn’t it be more powerful if we used Reacts hook chaining to update our asynchronous call!? Yes! Let’s modify the above code to show the flexibility of chaining and hooks.

In our new dynamic approach, we used the chaining abilities of React hooks and inject the newly selected url into the useAsync utility. Now any time a user selects a new url, we get a state update. That then updates our fetch params, pretty nifty right?

HOC: useAsync

The utility we created for asynchronous calls is a handy way to tie long-running tasks directly to a button. However, in some cases it would be significantly easier to automatically wrap useAsync within our code. This would allow isolation of async calls and their reactions scoped to an internal component structure. Continuing what we did earlier in the Theme provider, lets create a slim HOC for the useAsync utility.

With this new HOC, we can more closely tie the useAsync hook into an internal component.

Our PageFetch example now has the useAsync response directly injected into its props. Now we can modify the select example and isolate page fetching to its own Component.

The power of this might seem a little obfuscated, but imagine a tag input that makes requests to an endpoint and updates its suggestions dynamically. Now think of how insular and decoupled that could be in respect to its parent container!

Wrapping Up

Hopefully through the examples you have seen how impactful this change can be. What you can accomplish by migrating certain React components to use hooks, and how simplified business logic can be isolated within a re-usable context. Also, if you are interested, please check out my library and star it on github. Thanks for reading.

--

--