When Should You Convert Your Classes to Hooks??
Tags: react, javascript, hooks, oop
Published: 2020-04-21 23:47:54

Ever since the introduction of Hooks, questions have naturally lingered about 

* Should I _use_ Hooks?
* Should I convert my existing codebase to Hooks?
* All the cool kids are using Hooks.  I wanna be cool... _right_??

In the prior articles in this series, I've already done a lot of pontificating about Hooks: What's good about them.  What sucks about them.  And everything in between. 

This particular post assumes:

* You've been diving in with Hooks and you either A) love them, or B) want to steer more of your dev to them because they kinda feel like "the future" of React.<br/><br/>

* You're not working on a "green fields" project where you can make all the high-minded, theoretical choices about how the project will be built.  You're staring at a ton of class-based components.  And you're wondering when/if you should try to tackle _converting_ the legacy components to Hooks.<br/><br/>


## A Measured, Strategic Plan For Class-to-Hooks Conversion

So what do you do with all of those mean, ugly, nasty class-based components that are sitting in your otherwise-pristine React codebase?  Well, you're in luck.  

Over the last several months, I've been writing many _thousands_ of lines of new Hooks-based components.  I've also been converting _hundreds_ of class-based components into Hooks.  After all of this intensive effort, I feel that I've gained some unique insight on this matter, and I can now offer you a measured, strategic, step-by-step guide that explains exactly _how_ and _when_ you should convert your classes to Hooks.


## Step 1

> Put your hands up and slowly walk away from the keyboard.  Go have a beer.  Chat with some friends.  Binge-watch _Tiger King_, for the third time, while you're waiting out the quarantine.  No matter what you actually choose to do, you are, by no means, to actually start _converting_ any of your React classes to Hooks.

Sound simple?  It is.  It's a gentle way to "ease into" the classes-to-Hooks migration process.  The real work won't begin until we get to Step #2.


## Step 2

> `GOTO` Step #1.  Repeat this entire process, as many times as necessary, until the whole "I must convert the class-based components" bug finally clears your system.  Don't be ashamed to call for help.  You might need some non-Hooks pals to come over and take you out for a night of Bowling & Boone's Farm.  Or you may need to rekindle that hard-drug habit you had in your teens.  Whatever works for you.  Just make sure that _you do not sit back at your keyboard and start converting your classes to Hooks_.

That's it.  There are no other factors to be considered with regard to your legacy, React, class-based codebase.  

You're welcome.


## The Refactoring Demon

If this all sounds like a joke, it really isn't.  You see, I've been doing a lot of work lately (_too much_ work), mired in the weeds of transmogrifying classes into Hooks.  I'm by no means an expert on them, but I've already seen, through gobs of my own code, where Hooks shine - and where they _don't_.  

There's a lot about Hooks that I'm legitimately _enjoying_.  And if you tell me that all of your _new_ code is now done in Hooks, then... _Great!_  I have no problem with that whatsoever.  

But let's just be honest with each other here, OK?  If you were the kinda person who was content to have _one part_ of your code using a given paradigm, and _another part_ of your code using another very-different paradigm, then you probably wouldn't be a programmer in the first place.  It's quite difficult to be a solid, talented developer and not be at-least-a-little OCD about your code.

So the more functional components you write, with all that juicy Hooks goodness baked into them, the more you're gonna feel that Refactoring Demon staring over your shoulder.  Every time you write another functional component, and then you have to flip _back_ into a file for a class-based component, your developer eye is gonna start twitching.  Little beads of sweat are gonna start breaking out on your forehead.  Your foot will start tapping uncontrollably.

Sooner or later... you're gonna think:

> Screw it!  I'm just gonna put in "a few extra hours" to convert these old class-based components into Hooks.  

And once you start down that path, the Refactoring Demon's got you firmly in its grip.  And you may not appreciate the end result after the Demon's had its way with you.


## Tune Out The Fanboys

If you turn off your headphones for a minute and listen carefully, you can almost hear the fanboys.  They're lighting their torches.  They're sharpening their pitchforks.  And they're already chanting, somewhere off in the distance, something like:

> Yer just old and stooopid and you hate modern React!  

But this post isn't about "Hooks are Da Sux" or "Hooks are Da Shiznit".  This post is about the (meager) relative benefits of _converting_ class-based components into Hooks.  

Do you love Hooks??  Awesome!  Nothing in this post is trying to dissuade you from that position.  (As if I could, even if I tried...)  This post is about the question/challenge that's represented by the many _millions_ of lines of class-based code that are already out there, "in the wild".  

And I'm here to tell you that you should make every effort to _avoid_ migrating legacy class-based components to Hooks.  It has the potential to be a horrific waste of time and energy.  And it will probably yield minimal benefits.


## Meager Returns

Hooks _do_ have benefits, and class-based components _do_ have downsides.  And despite what the latest React fanboys will tell you, class-based components _do_ have benefits, and Hooks _do_ have downsides.  So if you're faced with a large legacy codebase of class-based components, you have to think very carefully before you blindly dive in with a wholesale rewrite.  

Will the _benefits_ of the new Hooks-based components be enough to outweigh the additional time/testing/headache that's necessary to convert your old classes to them?  In my experience so far, the answer has been a firm, "No." 

In the other posts in this series, I go into more detail explaining the relative merits and demerits of Hooks and classes.  So I won't regurgitate all that data here.  I will just offer a quick synopsis of a few key points:

1. Despite the ravings of some who worship at the Church of Functional Programming, functional components are not, hands-down, far-smaller and sleeker.  In some cases, the functional components are _a little_ smaller.  But too often, what FP enthusiasts call "smaller" is really just "we moved nearly all the code into these 12 separate helper functions."<br/><br/>

1. Some things with Hooks are nominally "better" - like the use of the Context API, and _some_ aspects of state management.  But other aspects of functional components are far _worse_ - like lifecycle management.<br/><br/>

1. Those legacy class-based components were written _by somebody_.  That "somebody" might still be on the team - and they might have a far better "feel" for class-based components.  Just as functional components might _feel_ better to you, I assure you that there are still people out there - talented, experienced people - who feel the opposite.<br/><br/>

But regardless of where you stand on any aspect of Hooks-vs-classes, the simple fact is that:

> There is nothing that you can do with Hooks that you simply _cannot_ do with class-based components (or vice versa).

This means that, if you've embarked on a big classes-to-Hooks refactoring project, at the end of said project, you should find that your app... does the exact same thing that it did before.  Oh, sure - _while_ you're refactoring, you might decide to add in some new features, or clean up a few lingering edge-case bugs, but these upgrades won't occur _because_ you've moved to Hooks.  They will only happen _as a side effect_ of the Hooks migration. 


## Not-So-Straightforward

If you Google things like "Hooks tutorial" or "convert React class to Hooks", it's all-too-easy to find a long series of one-pagers that purport to teach you how to migrate from classes to Hooks.  And like most tutorials, they're good for getting you _started_... and not much else.  They show you simplistic scenarios that can be converted with the least amount of effort.  But the tutorials map only-minimally to "real life" code.

You might be thinking:

> Dooood.  It shouldn't take long at all to convert a class-based component to Hooks. 

And often... it _doesn't_ take that long.  My experience with class-to-Hooks migration has followed a typical Pareto analysis.  Meaning that, about 80% of the original classes were converted - quickly and easily - with only about 20% of the overall effort.  But then you have the other 20% of your class-based components...

When you have a component that's doing a lot of fancy stuff with lifecycle methods, there's a good chance that the conversion to a functional component may not be fun.  If you have asynchronous elements (like API calls), that could also be painful.  Hooks are very good at state management, but _certain types_ of state tracking are not a one-to-one conversion from classes to Hooks.  If you have other large frameworks/libraries stuffed into the middle of your class-based components, it can be quite challenging to "translate" them to Hooks.

With all of the requisite _gotchas_ in mind, many of your class-to-Hooks conversions will be fast, easy, and even _pleasurable_.  But some of them... won't.  And the ones that won't will absolutely drag down your migration project.


## Cascade of (Refactoring) Sadness

On several occasions, my classes-to-Hooks migration has triggered a Cascade of Sadness.  Maybe you're unfamiliar with that phrase - but I doubt you're unfamiliar with the concept.

You start making the relatively minor syntactic changes that are needed to turn a class into a function-with-Hooks.  Then you find that one of your legacy packages doesn't want to play right with the Hooks (non)approach to lifecycle management - so you swap it for something else.  Then you realize that some of your class methods should really be refactored into custom Hooks.  Then you start chasing down all the places where your new, custom Hook should be used.  Then you...

Well, you get the point.  Before you know it, the supposedly "simple" migration from a class-based component into Hooks has become a Rabbit Hole of Doom.  At some point, you realize that you've been working on this _one_ class, and all of the domino effects that come from changing it, for several _days_.  And all of this is for a component that previously worked _just fine as it was_.

> At this point, I firmly believe that, if you are migrating a _large-scale_ application from classes to Hooks, you're not _refactoring_ it, you're _re-architecting_ it.


## A Schizophrenic Codebase

Hooks sound like a grand idea - when you're doing "green fields" development.  Now look back over your last 5-10 years of professional software work and think of how many times you've been lucky enough to do "green fields" development.

If you decide to implement Hooks, I fully understand why you probably _want_ to rewrite all your legacy components.  But Hooks aren't just a new keyword, or a simple shorthand syntax, or an additional convenience function that's been built into the core language.  

You've probably read some (or all) of the Hooks documentation that's available right alongside the "regular" React docs.  In that documentation, they're very clear in stating that Hooks can live right alongside your old-skool class-based components.  And that's true... sorta. 

When I look at my Hooks-based components next to my class-based components, they almost feel like they're part of two entirely different frameworks.  I've already received feedback from some other React devs who state that they just have a hard time _grokking_ what's going on in the class-based components.  

If you're stewarding a legacy React codebase, this can be extremely frustrating.  It forces your dev team to switch back-and-forth between two (sometimes radically different) paradigms.  Granted, a "senior, experienced, professional" programmer _should_ be capable of making such leaps.  But it's usually preferable to _avoid_ such leaps altogether. 

I've had the experience of having to work in a PHP codebase that used Drupal _in one section_ of the app, and Joomla _in another section_.  And let me tell you:  **It sucks.**

This is why I have a bit of a problem with the Hooks team's confident statement that you can just start sprinkling Hooks into your codebase wherever and whenever you see fit - and you can just leave all your legacy class-based components as-is.  This may be, technically, true.  But it's not conducive to crafting a _tight_ codebase or an _efficient_ dev team.

I haven't experienced this yet, but I have a strong fear that, at some gig in the not-too-distant future, I'll be on a team where work on large swaths of the app is commonly delegated to Joe & Mary - because Joe & Mary are the ones who wrote the Hooks-based components, and that's what _they're_ comfortable with.  Similarly, work on _other_ large swaths of the app may commonly be delegated to Bob & Susan - because Bob & Susan wrote a lot of the legacy class-based components, and that's what _they're_ comfortable with.

But if you start cranking out a ton of Hooks-based components, _right alongside your old class-based components_, at some point you're going to have a codebase that looks like that Drupal/Joomla Frankenstein that I described above.


## Caging The Refactor Demon

Despite my snarky guidelines at the top of this article, I'm not trying to say that there is _never_ a use-case for rewriting your old class-based components.  Here are a few things to keep in mind.

1. **Class/Hooks Ratios**<br/>If you have 100 class-based components and 5 new Hooks-based components, _do not_ embark upon some Quixotic quest to rewrite the 100 class-based components.  Just... don't.  _But_, if you only have a handful of class-based components lurking around your app, and you've since added 100 Hooks-based components, then I could totally understand the impetus to migrate the class-based components.<br/><br/>

1. **Segmenting Into Applications**<br/>Have you ever seen a React app with dozens of different modules?  And hundreds of thousands of lines of code?  And have you ever wondered whether they really _should_ be part of one, monolithic applications??  If so, this might be a prime opportunity to decide which _pieces_ of the original, legacy app can safely be ported off into their own standalone application.  Once you've decided that the Big Hairy Legacy App should really be five, unique, smaller apps, it's a prime opportunity to decide _which_ of those smaller apps might be excellent candidates for Hook-ification.<br/><br/>

1. **Segmenting Into Modules**<br/>If you already have a Big Hairy Legacy App that does many different things, there's a good chance that it's also divided into certain _modules_.  Assuming that's the case, it's much more feasible to decide that _this given module_ will heretofore be a Hooks-based module.  It's a much-lighter cognitive load for your fellow devs if they can see that everything in Module X uses classes, and everything in Module Y uses Hooks.<br/><br/>

1. **Reserving Hooks For Broader-Scope Refactoring**<br/>I've spent a lot of words explaining why it's probably a bad idea to migrate your classes to Hooks.  But that mostly applies if you're doing the migration _for the sake of doing the migration_.  In other words, if you're converting a class-based component to Hooks just because you're offended by the mere sight of that scary `class` keyword, then I feel strongly that you should really be leaving that component alone.  But there are other, more legitimate, reasons to do refactoring.  Most legacy codebases have at least some crotchety old components that are insanely large and complex.  New edge-case bugs are found in them every month-or-so - and someone is repeatedly tasked with going in and tinkering with the already-brittle logic.  In those cases, you may have been itching to refactor that eyesore anyway.  And if you are, it _might_ be an acceptable time to pull out your Hooks-Fu.<br/><br/>

1. **Refactoring For Education**<br/>I freely admit that I didn't have much "real world" experience with Hooks until a few months ago. When I realized that my new team would be working almost exclusively with functions/Hooks, I took the opportunity to begin refactoring a large side project on which I've been toiling for a few years.  I took this approach because I knew there would be "gotchas" and I didn't want to discover those "gotchas" while I was writing/delivering code for my employer (i.e., the place that actually _pays_ me to write code).  Quite frankly, I'm glad that I decided to spend all this _personal time_ refactoring a large, _personal_ project - because it's taught me _a lot_.  But this luxury isn't typically available to you when you're working "on the clock".  And if you embark on a wholesale classes-to-Hooks migration in the middle of a _production project_, you'll probably be wasting a lot of your employer's time and money.<br/><br/>