Why React-Redux hooks could replace the need for Thunks in your React projects.

Photo by Daniel Schludi on Unsplash

A Thunk is defined to be a dull, heavy sound, such as that made by an object falling to the ground. Oh wait… that’s the literal interpretation of the onomatopoeia. Although, if by the end of this article you agree with my premise, the literal description of a Thunk might be fitting, as a Thunk in the React environment may very well be obsolete.

A Thunk in React land is essentially a work around to allow for calling asynchronous functions that can subsequently dispatch actions to a Redux store. Thunks have to be wired up as a middleware in order to accomplish this work-around, which is unfortunate and messy and luckily I have generators that start my projects so that I don’t have to do this on my own each time. Consider Listing 1 as an example of applying Thunk as a middleware to a configure-store.ts file.

Listing 1 — Adding ThunkMiddleware to a configure-store function.

This store is now wired up to use dispatch functions that generate either normal Redux actions or asynchronous Thunk actions. Listing 2 demonstrates an asynchronous Thunk action that could be dispatched to a store that is generated by the function that is exported as the default export in Listing 2.

Listing 2 — An asynchronous action that dispatches an action upon completion of an http call.

As you can see, in order to create an asynchronous action with Thunk, your action generator must return a function that takes the dispatch function as its sole argument. Inside that function you can then perform whatever asynchronous function you want with access to the dispatch function in the body. So, in this example, when a component calls dispatch(getDataWithThunk()) , it will make an http request to an unspecified url (just assume there is a real url in the code example) and then the data that is return by this http call will be provided as an argument to the setData action generator and dispatched to whichever Redux store the Provider component has configured in your React app. This is useful and, prior to React hooks, was the preferred way to accomplish asynchronous actions with Redux.

However, you just as easily could have written this with an anti-pattern and imported the dispatch function directly from the store that you provided to your Provider component. This would be considered a singleton pattern and would be frowned upon in most cases. This is because in most cases you want your components, actions, and reducers to all be modular and testable in isolation. By using the singleton pattern (as demonstrated in Listing 3) you create a tight coupling between a single store and the components using that store.

Listing 3 — The anti-pattern of dispatching directly from a singleton store.

While it is an anti-pattern, it does show how one could accomplish dispatching data to a store after an asynchronous call without using a Thunk. So, can we do better? Can we accomplish eliminating Thunks from our projects without needing to use the singleton pattern? That’s where hooks come in. Now that React has introduced hooks, and the React Redux library has begun to use them, I would argue that Thunks are no longer necessary. Consider Listing 4 where I create a custom hook using the useDispatch hook from the React Redux library.

Listing 4 — Creating a data service custom hook.

In this example, I create a data service hook that can be instantiated inside a component. This hook returns a getData function that can be destructured when using within a component. It is considered a custom hook because it uses a hook within in and it returns values that can be used within a component. The useDispatch hook will infer from the calling component which store is configured to the closest Provider parent component and dispatch actions against that store, thus eliminating the need to use a singleton pattern. Listing 5 demonstrates how you would use this custom hook in a functional component.

Notice how the useDataService custom hook returns the getData function as a destructured variable that can then be used anywhere inside the component. In this example, the useEffect hook calls getData when the component mounts, which then dispatches the data returned from the http request to the redux store. The useSelector hook from the React Redux library then pulls in that data from the store to be used in the component and will trigger a component re-render any time the data that the selector returns changes. This demonstrates how a full asynchronous action can be created and used in its entirety using hooks instead of Thunks.

So, are Thunks obsolete then? I would love to hear from you in the comments below.

Jason Lee Hodges is a Software Engineering Team Lead and the author of “Software Engineering from Scratch.” You can learn more about the book or order it online here.