Using React Hooks in projects with existing class components

Prior to the release of React Hooks, we all used class components, higher-order components and React lifecycle methods… they worked and are still working properly, but in some cases, they can also be a struggle to write. This so-called “old” style of writing code in React can sometimes be troublesome, unclean and hard to manage. And that’s where hooks come to the rescue!

This new style of coding sets many ReactJS developers’ minds at ease. But wait, it sometimes isn’t that easy to just flip the switch and use hooks. There are plenty of projects that are fully based on class components… and then there’s the unfinished projects.

What do we do with those? How do we approach further development of such cases? Well, I’ll give you some of the answers right here.

The focus of this blog will mainly be a comparison between class component and hooks style of coding, as well as what to do to transfer between the two. But before we start… if you would like to read more about the basics of using React Hooks, take a look at my previous blog post which explains how to write custom hooks in React.

Let’s get started with ReactJS hooks

Apps in React always revolved around using class components for stateful or smart components, and function components for stateless or dumb components. React’s core methods and properties such as state, lifecycle methods and re-rendering based on a change of state could only be used in sturdy class components. That is exactly why those types of components were mostly used inside projects. Such components made the magic of React work and were a correct way of using all the goods that the library offered.

In addition to them, functional components were used on the bottom level — structurally speaking. This solely means that the last, hierarchical part, which presents the view layer itself, was mostly functional components. It is a part of the app which doesn’t need state as it gets the data from their parents and renders elements to the client.

Class-based components are often used along with HOCs or Higher-Order Components. HOCs represent a function that takes a component as an argument and returns an upgraded component (which can be stateful or stateless). It is a pattern used for connecting class components to external packages such as React Router and Redux. keep this in mind as it will be one of the factors used for translating from classes to function components with hooks.

On the other side of the story, the new proposed way of doing React coding is with hooks. Hooks represent a way of “hooking” into React’s methods, and providing access to all of the great features that React is offering within a function component. Since hooks enable you to use the state, function components are no longer named stateless components. Writing code using hooks makes a ton of stuff more trivial to implement. It makes the code cleaner, more DRY and reusable, simpler and easier to work with… and that is especially true when it comes to maintenance, upgrading and adding new features. All in all, React hooks greatly reduce the amount of code one has to write.

Another aspect of hooks that is very important to remember is that hooks cannot be used within class-based components. That is because they already have a way of using React’s methods… but there is a catch. HOCs can be used to provide hooks functionality to the class-based components. Since HOC is actually a function, it can use all of the hooks that React provides and pass data as props to a class-based component.

Here’s an example of such a case:

const authStateHOC = (WrappedComponent) => {  
  const initialState = createContext({  
  authState: {  
  email: "",  
  password: "",  
 },
 });  

const authStateContext = useContext(initialState);  
  
return (  
  <WrappedComponent  
   {...props}  
   value={authStateContext.value}  
   setValue={authStateContext.setValue}  
  />  
  );  
};

So yes, components can actually be tweaked using the HOC pattern to enable the usage of hooks inside class-based components. However, this is not suggested as the HOC pattern is something that developers are moving away from. Hard issues that HOCs solved, such as reusing logic, are now all in hooks. On top of that, by using this pattern you could end up lost in callback loop hell.

So what’s the solution?

React docs suggest that class-based components will not be deprecated with newer versions. But it also does not recommend writing class components anymore, since hooks are considered the future and a way to go. It is stated that further development should be done with the new hook syntax. Why? Because everything that was possible with class-based components is now achievable by using hooks… and in a much simpler way.

So, what should we do with class components then? Well, refactoring could be an option, but it isn’t mandatory because support for classes isn’t going anywhere. Also, it could end up really costly if we were to look at time consumption and/or project’s financial status. And this is especially true if the project is massive in scope.

While it might sound amazing to rewrite applications in order to use hooks, it does come at the cost… and that should not be treated lightly. If you do end up taking the refactor approach, take into consideration all that it would take to rewrite the code, so that it can use hooks… for example, how long will it take, or how many people need to be working on it.

The second way revolves around writing all of the new code with function components and hooks. And when you see yourself working in an older environment with classes, try to refactor a component or a couple of them to use hooks. Every time you go back and modify or update a particular feature which previously used classes, try rewriting it into hooks. This approach will allow you to slowly, but surely improve your codebase… and make it simpler and easier to maintain.

Quite a big number of libraries now offers support for hooks. For example, the aforementioned React Router and Redux (which are one of the most popular packages available for React) support it. They are used in almost every React app. This also suggests that if your project used, for example, the container pattern with HOCs, you can now use it much more easily with hooks. It also offers hooks such as useDispatch, useSelector and more. The router is more accessible with useHistory, useParams and useLocations hooks.

Hooks can do everything a class component can… and their reusable, clean and simplified functions are just another reason to implement them into your workflow.

Let’s conclude this story of hooks and class components

Many paradigms and patterns are moving more and more toward functional programming. Functional programming has so far solved or simplified problems that developers have been facing when using the object-oriented programming paradigm… problems such as getting lost in the obscurity of the code, or its WET state.

With functional programming, developers can focus on more items of importance, such as proper implementations and problem-solving. Also, keep in mind that refactoring an application is not a mandatory procedure, and you should always consider what’s best for your team and the project itself.