Functional components are simpler and easier to test in comparison to class components. However, both of them have pros and cons and today you’ll learn the differences and when to use which type of components.
Photo by Andrew Ridley on Unsplash
Introduction
When I started learning about React, I wondered why there are different approaches on how to create a component. Over time, I learned the reasons and which benefits each of these approaches has. In this post I’m going to show you what I’ve learned, by explaining the differences of functional components and class components and when to use them.
Functional Component
Let’s begin with functional components. They are simpler than class components and they provide less functionality, but more of that later. Let’s have a look at an example:
import React from "react"; import PropTypes from "prop-types"; const Person = ({firstName, lastName}) => ( <div> <h1> {firstName} {lastName} </h1> </div> ); Person.propTypes = { firstName: PropTypes.string.isRequired, lastName: PropTypes.string.isRequired } export default Person;
As you can see, functional components are basically just the render function of a class component. You can access props, but they can’t have state. You also can’t use life cycle methods with functional components. Instead, they focus solely on the UI and not on the behavior of the app.
Also something worth mentioning: When you’re using functional components, you don’t have a this keyword to use.
Now let’s have a look at class components, before we compare them and work out their different use cases.
Class Component
Class components make use of the ES6 class syntax. Since classes can have methods, these components can make use of life cycle methods like for example componentWillMount and componentDidMount. Have a look at the above example, rewritten as a ES6 class component.
import React, { Component } from "react"; import PropTypes from "prop-types"; class Person extends Component { render() { return( <div> <h1> {this.props.firstName} {this.props.lastName} </h1> </div> ); } } Person.propTypes = { firstName: PropTypes.string.isRequired, lastName: PropTypes.string.isRequired } export default Person;
As you can see, class components extend from React.Component, and you have to use the this keyword to access props (and also other functions you declare inside the component).
Usage
But what are functional components good for, if they don’t have state and life cycle methods? Why couldn’t you instead just always use the ES6 class syntax? I’ll tell you how I think about that:
Presentational and Container Components
Functional components seem a bit more lightweight, they are simpler and a bit easier to read. Most of the components you will write, don’t need state. Dan Abramov, the creator of Redux, wrote an article about different types of components: Presentational and Container Components, also known as smart and dumb components. The way he sees these components inspired me to also take on this mindset.
- Presentational Components focus on the UI and don’t have their own state, therefore I create them as functional components. If needed, you can always rewrite them to class components later on, but most of the time you will just use them to arrange your UI and let the container components handle the state and logic.
- Container Components need their own state or make use of life cycle methods, therefore I create them as class components.
State and Life Cycle Methods
I already mentioned before, that functional components are stateless and that they also do not support life cycle methods. In such cases, you should simply create a class component.
Benefits of using Functional Components
Even if you can’t have state, use life cycle methods or use the this keyword (is this even a disadvantage?), functional components provide some benefits that make them worth using.
Simplicity
Functional components are simple. If you use them, you’ll spare a few lines of code. And because of their lack of state and life cycle stuff, they only focus on how the UI looks. This allows us to find bugs faster, or avoid putting them in.
Testability
Also, since they don’t have any side effects, functional components are pure functions. This makes them easy to test. You put something in, and get something out. No matter if you do this once, twice or five hundred times, if you call the function with the same arguments, you will always get the same results.
Best Practices
Last but not least, instead of just adding a little bit state here and there, as soon as you need it, functional components encourage you to use best practices, elevate state to where it really belongs, use higher order components, etc.
In the next section you’ll learn a bit about the way I work with components.
My Take on Components
Keeping in mind what I’ve learned (and written above), I always create a concept of how my state will be spread over the different components. This way, I can easily identify possibilities to elevate the different parts of the state to a more appropriate level. You’ll see, that most of the components can be stateless, pure, functional components.
This doesn’t mean you should avoid stateful components at all cost. Try to keep them at a reasonable amount and profit from having lots of components that are easy to test and easier to refactor, which – in my opinion – is a good approach to keep the code and your application a bit cleaner and spare you some headache later on.
Wrapping Up
Today you’ve learned, that there are functional and class components. You learned, that functional components
- don’t have state
- don’t have life cycle methods
- don’t have a this
- are pure functions and therefore easy to test
- are easier to read and understand
- encourage you to keep in mind the best practices
- can also be called presentational components
If you need anything that functional components don’t provide, use class components.
Call to Action
Do you want to learn more about React, JavaScript and web development? Good news! Subscribe to my newsletter and get high quality content delivered right into your inbox, for free – on a weekly basis.
If you liked this article, you probably might also want to learn more about React Life Cycle Methods:
http://www.andreasreiterer.at/web-development/reactjs-lifecycle-methods/
Thanks for reading the article until the end! I would appreciate if you let me know what you think. So leave me a comment, contact me on Twitter or send an email to hi@andreasreiterer.at – I’m happy to respond to any message I get.
Nice article. Functional components can be used in container components as well, if the state is maintained in Redux. I use class components with state for custom reusable components that I write. For Mobx, I create reusable stores. And pair reusable components with reusable stores.
Thanks for reading!
You are right, if a component does not need to have a state on its own (or life cycle methods), I prefer to use functional components.
Like you said, if the state is maintained otherwise (Redux / MobX) it’s even better since most components won’t need their own state.
Classes also require instantiation, have a lifecycle, use more memory and are not as fast
In general, I find that a nice approach is to have one class-y “app-level” component per file, and then have a bunch of “ui-level” functional components in the same file that implement the DOM side of things.
I avoid writing any DOM-related props in the “app-level” component, thus making it easy to reason about its functioning without worrying about presentation. If I need a special structure, e.g. div-in-div, just to make some layout work, that’s for the functional components.
Styled-components is a great complement library for this.
I also handle it somehow like that.
If there are a lot of small functional components I’ll put them into one file – especially when I’m working with styled-components.
The rest is just composition of “ui-level” functional components and state management.