DEV Community

Cover image for 10 Reasons Why You Should Never Use React Class Components πŸ™…β€β™€οΈβ›”οΈ
Ndeye Fatou Diop
Ndeye Fatou Diop

Posted on • Edited on

10 Reasons Why You Should Never Use React Class Components πŸ™…β€β™€οΈβ›”οΈ

Whenever I encounter React code with class components, my heart cries πŸ₯².

Functional components have been the standard for years, yet I still see new React devs using class components.

In this article, I will share 10 reasons why you should avoid class components (plus the only case where you need them).

Ready? Let's dive in πŸ’ͺ .

10 reasons why you should avoid class components like the plague

Reason #1: They are strongly discouraged by the React team

The React team strongly discourages the use of React class components πŸ˜….
As a result, if you decide to use them:

  • You won't get any new features related to class components.
  • You won't receive help or get any PDS tickets resolved.
  • You will have a harder time upgrading your version of React since you will need to handle breaking changes.

Reason #2: They are less concise than functional components

A software program should be as concise as possible without losing readability.
There are several reasons for this:

  • The more concise the code, the easier it is to read/modify.
  • The less code, the fewer bugs in general.
  • Code with a lot of boilerplate obscures the actual intention/business logic.
  • The fewer code changes you have in your PR, the faster it gets reviewed. If I see a 50-line change, I will generally review it before a > 300-line change πŸ™ˆ.

For all of these reasons, you should prefer functional components. They are more concise than their class equivalent.

See the example below, where the same code is expressed with a class and functional components πŸ‘‡.

❌ Bad: This code is more complex than it needs to be.

class Form extends Component {
  state = {
    email: "",
    password: "",
  };
  render() {
    return (
      <>
        <p>
          Email:{" "}
          <input
            type="email"
            value={this.state.email}
            onChange={this.onEmailChange}
          />
        </p>
        <p>
          Password:{" "}
          <input
            type="password"
            value={this.state.password}
            onChange={this.onPasswordChange}
          />
        </p>
      </>
    );
  }
  onEmailChange = (event) => {
    this.setState({ email: event.target.value });
  };
  onPasswordChange = (event) => {
    this.setState({ password: event.target.value });
  };
}
Enter fullscreen mode Exit fullscreen mode

βœ… Good: The code is more concise.

function Form() {
  const [{ email, password }, setState] = useState({
    email: "",
    password: "",
  });
  const onEmailChange = (event) => {
    setState((prevState) => ({ ...prevState, email: event.target.value }));
  };
  const onPasswordChange = (event) => {
    setState((prevState) => ({ ...prevState, password: event.target.value }));
  };

  return (
    <>
      <p>
        Email: <input type="email" value={email} onChange={onEmailChange} />
      </p>
      <p>
        Password:{" "}
        <input type="password" value={password} onChange={onPasswordChange} />
      </p>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Reason #3: Class components have a ton of lifecycle methods, and many of them will be deprecated in future versions of React

I used to be so confused by React because of all the lifecycle methods: componentDidMount, componentDidUpdate, etc.
I was never sure which one to use and was frankly annoyed that I had to write so much code πŸ˜’.
Now, with functional components, this is no longer a problem. You still need to be familiar with a component lifecycle, but you don't need those concepts to write a component.
Additionally, many of these methods, like componentWillUnmount, componentWillUpdate, etc., will be deprecated in future React versions. So you can save yourself some migration pain by stopping to use them.


Reason #4: You have to be very careful to bind your class methods to the class instance or declare your methods as arrow functions

This is not a React problem but more something due to how this works in Javascript.
In fact, the value ofΒ thisΒ depends on the context in which it appears: function, class, or global.
The example below shows a bug 🐞 in the code because when onEmailChange and onPasswordChange are invoked, this is undefined. As a result, you see an error as soon as you start typing.

To fix this, there are two options:

  • Option #1: Bind onEmailChange and onPasswordChange inside the class constructor
  • Option #2: Declare onEmailChange and onPasswordChange as arrow functions

Reason #5: Class components can only read one context at a time

In the latest versions of React, you can only access one context at a time in a class component using contextType.
There are workarounds around this, but they make the code more complex.


Reason #6: Using componentDidMount often requires using componentDidUpdate and componentWillUnmount

Unfortunately, as soon as you start using componentDidMount, you may need to pair it with componentDidUpdate and componentWillUnmount.
With functional components, a simple useEffect hook is generally enough.

In the sandbox below, you can see that FunctionalComponentDashboard is 30 lines while ClassComponentDashboard is way longer at 96 lines.


Reason #7: They prevent you from leveraging powerful tools like hooks

React hooks are amazing.

  • They are simple to set up and make "complex" techniques like higher-order components obsolete.
  • You can build your own or leverage external hooks like the ones on usehooks
  • Etc. Unfortunately, they are not supported inside class components, making code reuse harder.

Reason #8: Most of the documentation and courses use functional components now

It's nearly impossible to find new content about class components.
In fact, since functional components have been the standard for quite some time, they are taught in online courses or used in react.dev documentation.
So, using class components will put you at a disadvantage and make it harder for new developers to onboard with your codebase.


Reason #9: They can easily break tree-shaking (dead-code elimination)

Tools like Vite, Webpack, etc., optimize your code through tree-shaking (i.e., dead-code elimination).
This is done so that the files sent to users are smaller and they can download them faster.
Now, with class components, it is very easy to mess this up πŸ₯².
In fact, if you have a method that is not used and you forgot about it, it will also be shipped to the user since tree-shaking won't kick in.


Reason #10: They often result in bigger Javascript files

Class components are more verbose than functional components.
Thus, your app can be slower to start since the user has to download/process bigger files.
Additionally, if you need to support older browsers, they may not support class components πŸ€¦πŸΎβ€β™€οΈ.
So you will need a tool like Babel to take those class components and transpile (i.e., transform) them to valid JS code.

This will further increase the total file size (see the comparison below).

❌ Bad: With a class component, the resulting JS file is 1.9kb => Link

Babel with class component

βœ… Good: The resulting JS file is way shorter at 224 bytes => Link

Babel with functional component


πŸ’‘ The only exception

Unfortunately, there is no equivalent of the lifecycle method componentDidCatch for function components. However, this method is required when defining error enhancers. So, this is the only case where you absolutely need a class component.


Thank you for reading this post πŸ™.

If you were using class components, I really hope you stop using them πŸ₯°.

And Don't forget to Drop a "πŸ’–πŸ¦„πŸ”₯".

If you like articles like this, join my FREE newsletter, FrontendJoy, or find me on X/Twitter.

Top comments (0)