6 Reasons to Use React Hooks Instead of Classes
React hooks have been around for some time now, yet many React developers are not actively using them. I see two primary reasons behind this. The first reason is that many React developers are already involved in a large project, which requires a significant effort to migrate the entire codebase. The other reason is the familiarity with React Classes. With the experience, it feels more comfortable to keep using Classes.
In this article, we’ll look into five reasons why you should consider React Hooks.
1. You don’t have to refactor a functional component into a class component when it grows
Usually, there are times when a React component starts with a functional component, which only depends on the props and later evolves into a Class component with having a state. Changing from a functional component to a class component requires a little bit of refactoring, depending on how complex the component is.
With React Hooks, since functional components have the capability of tapping into the state, the refactoring effort will be minimal. Let’s consider the below example, a dumb component that shows a label with a count.
Let’s say we need to increment the count with mouse clicks and let’s assume this only affects this particular component. As the first step, we need to introduce the state to our component. Let’s take a look at how we would do that with a class-based approach.
The same component will look like the following if we use Hooks.
2. You don’t have to worry about “this” anymore
Classes confuse both people and machines
The above sentence is from React documentation. One of the reasons for this confusion is this
keyword. If you are familiar with JavaScript, you know that this
in JavaScript doesn’t work exactly like in other languages. When it comes to React Hooks, you don’t have to worry about this
at all. This is good for beginners as well as experienced developers.
According to the above example, you can see that we no longer have to use “this
” while accessing the state. This makes it less confusing for everyone.
3. No more method bindings
Now for the above same ShowCount component let’s introduce a method to update the count of the state when the user clicks on the label.
We have introduced handleClickEvent
method. To use it, first, we have to bind it to this
of the Component.
this.handleClickEvent = this.handleClickEvent.bind(this);
We have to do this because the execution context is different when the method gets executed. For a beginner developer, this might be a bit hard to understand.
Instead of binding all the methods, there are some syntax proposals where you can get around this. For example, we can rewrite the function to an arrow function.
handleClickEvent = () => {
this.setState({count: this.state.count + 1});
}
Let’s see how we can implement the same functionality with Hooks.
As you can see, we have only added the function. Also, you might notice that when we use the event handler, we have removed this
in the template.
onClick={ handleClickEvent }
4. Easier to decouple logic from UI, making both more reusable
Using hooks, logic and UI are easier to separate. No need for HOC or render props. Hooks do it elegantly with less boilerplate and more intuitive compositions of UI and logic.
This “elegant separation” is especially crucial when sharing components using tools and platforms like Bit (Github) as each (independently shared) component is much easier to understand, maintain, and reuse across different apps.
5. Keep related logic in the same place
Complex components become hard to understand
With the class-based approach, we have different life cycle methods such as componentDidMount
and componentDidUpdate
etc. Let's consider a situation where subscribing to services A and B in componentDidMount
and unsubscribing them on componentWillUnmount
. With time, there will be many logics included in both life cycle methods, and it will be hard to keep track of which part of mounting is related in unmounting.
To demonstrate this, let's create an RxJs based service to get the count. We will use this service to update the count in ShowCount example. Note that we will be removing the handleClickEvent
as we no longer need to update the component on click events.
You can see that inside the useEffect
we have included subscribing as well as corresponding unsubscribing logic. Similarly, if we need to introduce more service subscriptions or unrelated logics, we can add multiple useEffect
blocks to logically separate different concerns.
6. Sharing stateful logic between components
With the class-based approach, it is hard to share stateful logic between components. Consider two components where both have to fetch, sort, and display data from two different data sources. Even though both components have the same functionality, it is hard to share the logic because these components have different sources and states.
While we can use render props and higher-order components to solve this, it will also introduce additional cost as we have to restructure our components, which will eventually make it harder to follow.
What React Hooks offers?
With Custom React Hooks you can extract these reusable stateful logics and test them separately.
We can extract a custom hook from the ShowCount example.
Using the above custom hook, we can rewrite the ShowCount component as follows. Notice that we have to pass the data source to the custom hook as a parameter.
Note that we invoke
getCounts
in a parent component rather than inShowCount
component. OtherwiseserviceSubject
will have a new value each time it runsShowCount
and we wouldn’t get the result we expect.
Conclusion
While there are many reasons to switch to React Hooks, I have mentioned the most compelling reasons which made me change to React Hooks. If you look at the official documentation, you will see that there are many interesting functionalities with React Hooks. Please let me know in the comments about your journey to React Hooks.
You can find the completed source code here.