Thoughts on software design, testing, and everything in between.

March 5, 2018March 7, 2018

Why I Prefer Functional Components5 min read

One of the most common disagreements I see in React has to do with whether to use class or functional components. There are certainly merits to both approaches, but over the last few months, I’ve definitely come to favor one over the other.

I’ve discovered that when I write pure functional components I tend to write cleaner code. I’ve also found I have a much easier time returning to that code, figuring out what I was doing, and making changes to the behavior of the system.

Before I embark on this religious crusade enlightened debate, I want to clarify what I’m advocating. I’m not saying classes shouldn’t be used to create React components. They can, and perhaps should be, used to create certain components requiring functionality pure functions can’t provide (no pun intended). Instead, I’m encouraging developers not to only use classes. It’s tempting to “simplify” the code base by just making everything a class. But, as I’ll try to demonstrate below, it actually makes things more complex and harder to reason about.

So. now that that’s out of the way…

Let’s refresh, what do I mean by “functional” versus “class”?

Here I’m referring to two different ways of accomplishing the same thing: declaring a React component.

Functional syntax encourages smaller, focused components

Components written in a functional way give us access to a really concise interface devoid of boilerplate. You can use object destructuring to pull out any props you need. There are no lifecycle methods and no state. You often don’t need an explicit return, allowing you to write really small, focused components.

Sure, you can bloat them up but the syntax discourages that. Want to do some calculations before your return statement? You can, but you have to swap the parenthesis wrapping your arrow function with curly braces. As you continue extending the component with markup the sheer size and responsibility of it quickly becomes clear.

With a large class component, you can have a component that’s not doing a lot in spite of its size. Constructors, state management, lifecycle methods, and the class syntax itself all work together to hide the amount of work the component is doing and the number of responsibilities it has.

Not only are functional components harder to load with bloat, they also offer a nice incentive to breakout new components: it’s really easy. A simpler import and a tight syntax make creating new components a breeze. And, with each new one you create, you reduce the cognitive load required to understand the component you’re working on.

They’re easier to test

Functional components tend to be easier to test for a number of reasons. That alone makes my life much easier.

As we talked about above, they’ll tend to be smaller and have few responsibilities (hopefully just one). That’s great! I test for successful rendering, the appearing of key elements, and that props are used as I expect them to be. Then, I’m confident my component works as intended. If I have a class, I’m going to have to be very careful when designing the test. Even if it doesn’t have state, lifecycle methods, or functions I have to carefully check for each. That’s a fair amount of cognitive overhead for something that doesn’t exist.

If you practice TDD (and I encourage you to try it if you don’t), functional components fit nicely in the 30-second cycle of back-and-forth between writing failing tests and making them pass. You’ll find you have to write less code to get to a place where your tests pass. It might not seem like much, but when writing tests drive your development the little things add up in a big way.

They communicate a clearer interface

I think this point isn’t talked about enough. React components are functions and classes like any other domain. It’s easy to forget when we’re looking at a component full of JSX that it’s not HTML we’re looking at, but an object we’re designing that’s exposing an interface to other objects. In React, that interface takes the form of props – primarily, anyway.

Take a look at how different the expression of the interface is between the styles:

When we use a class syntax to define our component, the interface (props) is hidden within our render function. When we use a functional syntax we can take advantage of destructuring at the very top of our component, inside our function’s signature – which is exactly where it should be. You can look at the component and immediately know what props you need to pass in to make it work.

They’re much less noisy

Signal-to-noise is real. If you have a small five line component, a class will have more boilerplate than actual component. Functions, on the other hand, have hardly any noise at all. Even the declaration line is loaded with useful information, such as the props mentioned above. In fact, in that last example, literally most of the class-defined component was made of boilerplate.

Wrapping up

To be clear, there’s nothing wrong with class components. They work just fine and are sometimes necessary. The problem is they offer no constraints. There’s nothing hard about making them do too much. I’m sure a well-disciplined team with a rigorous code review process can prefer them and still write generally clean code. But they do make it easy to stray from best practices and developers, myself included, tend to do what’s easy.

That’s why I help myself by making it just a little harder to write messy code. It’s not a silver bullet, but it can help a great deal.

What do you think? Do you tend to prefer one style over the other? I’m curious if there are any points for classes or functions I neglected to mention here.

I used to prefer functional components too, but then I read somewhere that there is a drawback. Functional components re-render every time, no matter if the props changed or not. I’ve now started extending React.PureComponent instead of using functional components, because then shouldComponentUpdate is implemented by default, so that the component only re-render when state or props changes.

Whether this has much influence on performance or not, I’m not sure. But it made me switch back to class components.

I use to avoid functional components because they have a couple of drawbacks:

They are slower.
React wraps them into a class statement on runtime – this adds extra overhead. Minimal – granted – but still

You often end up converting them back to classes because:

– You suddenly need state during app changes
– You need to register some functions on the components scope to pass them down to subcomponents
– Some higher order functions from modules that add for example drag&drop functionality dont support functional comps

At the end you end up with classes here and functions there – I prefer to have it clean and just ONE type of comps. Even more because I am often working in big teams where it is crucial to work very clean.

I like your take on this. The article https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 comes to mind as functional components are definitely good for the small props driven components and the class components seem to be necessary when they fit more into the parent component category. Thanks for sharing. I’m glad I got another poke to give TDD a shot.

I agree with you, usually I write functional components, but sometimes I found that I need a state and so I have to refactor the code. To accomplish it in an easy way I wrote react-refactor, a tool to convert any React class component to a functional component and vice-versa https://github.com/chrvadala/react-refactor

Great point! I would have a hard time justifying tacking in a little something extra to a 5 liner..but if the thing is already 20 lines of boiler plate, then it just seems easier to slide my lil hack in.