Pluralsight Author, Principal
The differences above may seem subtle at first glance, but cutting the noise is a big win.
No Class Needed
Frankly, I think the drama around ES6 classes is overblown. But I do agree that plain functions are generally preferable, and eliminating the class related cruft like extends and the constructor in the example above are a nice win.
No this Keyword
Oh, as a side note, there are five different ways to handle binding in React. Here’s a short post on the merits of each approach.
Enforced Best Practices
Stateless functional components are useful for dumb/presentational components. Presentational components focus on the UI rather than behavior, so it’s important to avoid using state in presentational components. Instead, state should be managed by higher-level “container” components, or via Flux/Redux/etc. Stateless functional components don’t support state or lifecycle methods. This is a good thing. Why? Because it protects from laziness.
See, it’s always tempting to add state to a presentational component when you’re in a hurry. It’s a quick way to hack in a feature. Since stateless functional components don’t support local state, you can’t easily hack in some state in a moment of laziness. Thus, stateless functional components programatically enforce keeping the component pure. You’re forced to put state management where it belongs: in higher level container components.
High Signal-to-Noise Ratio
As you can see in the image above, stateless functional components require less typing. This translates less noise. As I discuss in “Writing Code for Humans”, great code maximizes the signal-to-noise ratio. The 27 line component became 21 lines, a ~20% reduction. You can go a step further on simple components. With a single line return statement, you can omit the return and curly braces. If you do this and also use ES6 destructuring on props, the result is nearly all signal:
It’s a function that takes a parameter and returns markup. Nice. Seriously, could this feasibly be any cleaner?
If you destructure your props in ES6 as I did in the example above, then all the data you use is now specified as a simple function argument. This means you also get improved code completion/intellisense support compared to class-based components.
Bloated Components and Poor Data Structures Are Easily Spotted
We all know a function that takes a lot of parameters is a code smell. When you use ES6 destructuring with your stateless components, the argument list clearly conveys your component’s dependencies. Thus, it’s easy to spot components that need attention. In this case, you can either break up the component or rethink the data structures you’re passing around. Sometimes a long list of props can be easily resolved by passing an object instead. But if the props aren’t logically related enough to justify a single object, then it’s likely time to refactor the component into multiple separate components.
Easy to Understand
As we’ve just seen, when you see a stateless functional component, you know it’s simply a function that takes props and spits out HTML. Even if it contains a lot of markup and nested functions inside the render, it’s conceptually simple. It’s a pure function. This leads to the next big win…
Easy to Test
Since it’s a pure function, your assertions are very straightforward: Given these values for props, I expect it to return this markup. So for the example HelloWorld component, I can assert that when the render function is called with the value of ‘Cory’ for props.name, it returns a div with ‘Hi Cory’ inside.
With React’s stateless functional components, each component can be easily tested in isolation. No mocking, state manipulation, special libraries, or tricky test harnesses are needed.
Finally, stateless functional components may soon offer improved performance as well. Since there’s no state or lifecycle methods to worry about, the React team plans to avoid unnecessary checks and memory allocations in future releases.
Update: With React 16.6+, you can declare “pure” functional components via React.memo. And with Hooks in 16.7, functional components transpile smaller too.
Even today, functional components transpile down to less code than class components, which means functional components = smaller bundles:
Improved performance with superior syntax, testability, and readability? Sign me up!
Yep. See my other post, “7 Reasons to Outlaw React’s Functional Components”, for the potential downsides to consider.
For all these reasons, we should strive to use stateless functional components wherever possible. Stateless components are just the latest reason why I love teaching React. React stateless functions offer the most elegant approach I’ve seen for creating a reusable component in any popular framework. Yes, even including Angular 2.
Are there other wins I’m overlooking? Downsides to consider? Chime in via the comments below.
Cory House is principal consultant at reactjsconsulting.com. He is the author of “Building Applications with React and Redux in ES6", “Building Applications with React and Flux”, “Clean Code: Writing Code for Humans” and multiple other courses on Pluralsight. He is a Software Architect at VinSolutions and trains software developers internationally on software practices like front-end development and clean coding. Cory is a Microsoft MVP, and founder of outlierdeveloper.com.