avatarsupraja

Summary

In React, functional components have become the preferred choice for developers due to their simplicity and the added capabilities provided by hooks, which allow them to manage state and lifecycle events previously exclusive to class components.

Abstract

React developers primarily use two types of components to build user interfaces: functional and class components. Historically, class components were the go-to for managing state and lifecycle events, while functional components were limited to rendering UI elements. However, with the introduction of hooks like useState and useEffect, functional components can now perform all the tasks of class components, making them more versatile and easier to work with. Functional components are praised for their straightforward syntax and ease of testing and debugging. Despite this, class components still have their place, particularly in legacy codebases or for specific features like error boundaries. The React community is increasingly favoring functional components for their simplicity and the ability to write less code without sacrificing functionality.

Opinions

  • Functional components, enhanced by hooks, are seen as a more straightforward and modern approach to component development in React.
  • The React community values the simplicity and readability of functional components over the complexity of class components.
  • The evolution of functional components has made the term 'stateless' obsolete, as they can now manage state and lifecycle events just like class components.
  • Developers appreciate the ability to mix class and functional components within a React application, offering flexibility in component design.
  • There is an acknowledgment that class components are still relevant in certain scenarios, such as for error boundaries, but hooks have reduced the need for them in many cases.
  • The preference for functional components is driven by the ease of use, testing, and debugging, which contributes to a more efficient development process.

Functional Components Vs. Class Components in React

image credit: link

Overview

In the world of React, components are like building blocks for creating user interfaces. There’s been a lot of talk about two main types of components: class-based and functional. Understanding the differences between them is key for any React developer.

Introduction

Imagine you’re building a complex structure, like a house, with different types of bricks. In React, components are like those bricks. They help us create the user interface by breaking it down into manageable pieces.

What Are Functional Components?

Functional components are the simpler type of components in React. They’re basically JavaScript functions that return JSX (which is like HTML). Here’s a simple example:

function WelcomeMessage(props) {  
  return <h1>Welcome, {props.name}</h1>;  
}

Functional components used to be limited in what they could do, but with the introduction of hooks, like useState and useEffect, they can now manage state and handle lifecycle events just like class components.

Functional components are great when you have a small piece of UI that doesn’t need a lot of logic to manage its state. They’re easy to write and understand because they’re so simple.

What Are Class Components?

Class components are a bit more complex. They’re based on ES6 classes and extend from React.Component. Here's an example:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Class components are good for managing state and handling more complex logic. They come with a bunch of built-in methods for managing the component’s lifecycle.

But because they’re more complex, they can be harder to read and write, especially for beginners.

A mix of class and function-based components:

Just to give some idea on implementation, it is possible to use a mix of class-based and function-based components in a React application. You can freely use both types of components in your app.

// App.js
import React, { Component } from 'react';
import FunctionComponent from './FunctionComponent';
import ClassComponent from './ClassComponent';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      message: 'Hello from the parent component',
    };
    this.updateMessage = this.updateMessage.bind(this);
  }

  updateMessage(newMessage) {
    this.setState({ message: newMessage });
  }

  render() {
    return (
      <div>
        <h2>{this.state.message}</h2>
        <FunctionComponent updateMessage={this.updateMessage} />
        <ClassComponent message={this.state.message} />
      </div>
    );
  }
}

export default App;
// FunctionComponent.js
import React from 'react';

const FunctionComponent = ({ updateMessage }) => {
  return (
    <div>
      <button onClick={() => updateMessage('Message updated by FunctionComponent')}>
        Update Message from FunctionComponent
      </button>
    </div>
  );
};

export default FunctionComponent;
// ClassComponent.js
import React, { Component } from 'react';

class ClassComponent extends Component {
  render() {
    return (
      <div>
        <h3>Message in ClassComponent: {this.props.message}</h3>
      </div>
    );
  }
}

export default ClassComponent;

In this example, we have an App component that maintains the state with a message. It renders both FunctionComponent and ClassComponent. FunctionComponent is a function-based component that contains a button to update the message via the updateMessage function passed down as a prop. ClassComponent is a class-based component that receives the message as a prop and simply displays it.

When the button in FunctionComponent is clicked, it updates the message in the parent App component's state, and this change is reflected in the ClassComponent as it receives the updated message as a prop.

NOTE: In React class components, the context (this) of class methods like updateMessage() is not automatically bound to the class instance. This means that if you directly reference this.updateMessage in the onClick handler without binding it explicitly, the this keyword within the updateMessage() method would be undefined or refer to a different context when the method is invoked, leading to runtime errors. Let’s breakdown and understand constructor code in class-based component:

  1. constructor(props): This is a special method used to initialize the component when it's created. It sets up the initial state and binds methods.
  2. super(props): This calls the constructor of the parent class, which is necessary for setting up the component correctly, especially when dealing with inheritance.
  3. this.state = { message: 'Hello from the parent component' };: This line sets the initial state of the component. State is used to store and manage data within a component.
  4. this.updateMessage = this.updateMessage.bind(this);: This binds the context of the updateMessage method to the component instance. It ensures that the method can access the component's properties and methods correctly when it's called.

A Closer Look at Class vs. Functional Components

Rendering JSX

Both types of components do the same thing: they render JSX, which describes what the UI should look like. Functional components return JSX directly from the function, while class components use a render() method to do the same thing.

Passing Props

Props are pieces of data that you can pass from one component to another. Both types of components can receive props, but the syntax is a bit different. Here’s how you do it:

// For a Class Component
class ClassComponent extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

// For a Functional Component
function FunctionalComponent(props) {
  return <h1>Hello, {props.name}</h1>;
}

Handling State

State is data that changes over time in a component. Historically, class components were used for managing state. But now, with hooks, functional components can do the same thing. Here’s an example of both:

// In Functional Components
const FunctionalComponent = () => {
  const [count, setCount] = React.useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

// In Class Components
class ClassComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment
        </button>
      </div>
    );
  }
}
Functional vs Class Components

The Evolution of React Components: From Class to Functional

Functional components changed the game by allowing us to do almost everything a class component can do, but in a more straightforward way, thanks to hooks. Let’s unpack this a bit:

  1. React Hooks: These are functions that let you “hook into” React’s state and lifecycle features from function components. They’re a bridge to the power traditionally reserved for class components.
  2. Stateless No More: The term ‘stateless’ used to apply to functional components because they couldn’t hold state. Not anymore. The useState hook gives these components the ability to keep track of state data.
  3. Lifecycle: Unlike class components, functional components don’t come packed with lifecycle methods out of the box. But don’t worry, the useEffect hook lets us mimic the lifecycle behavior — managing side effects in our component.
  4. When to Use Functional Components: Think of functional components as the best choice for most situations. If your component is more like a piece of a puzzle — not too concerned with what the other pieces are doing — then a functional component is your go-to.
  5. Keep It Simple: If you like writing less code and keeping it readable, functional components are your friends. They’re straightforward and much easier to test and debug.

Let’s further clarify these concepts with a simple illustration:

Imagine you’re building a house (your app), and you have two tools (component types) to choose from. One tool is a multi-purpose, somewhat bulky Swiss Army knife (class component), and the other is a simple, sharp pocket knife (functional component). While the Swiss Army knife has many features you might not need all the time, the pocket knife is easy to carry and handle, perfect for most tasks.

So, why choose the bulkier tool when the sleeker one does the job just as well, if not better in most cases? That’s the choice React developers face, and many are picking the pocket knife — functional components equipped with hooks.

Knowing When to Use Each Component Type

So, when do you choose one type of component over the other? Well, if you’re doing most things in React nowadays, functional components are likely what you’ll use. They’re the current favorite for their simplicity and ease of use. Plus, the React team is pushing updates that make functional components even better.

Class components are still around, especially in older codebases, and there are times when they’re useful. One example is when you’re dealing with error boundaries — a feature for catching JavaScript errors in your component tree which is currently only possible with class components.

Functional components are ideal for presentational components with no state or lifecycle hook needs. Class components are more suitable for error boundaries and other legacy patterns. However, even in these cases, hooks can often mimic the desired behavior without using class components.

Summary

React components are like building blocks for creating user interfaces. Functional components are simpler and easier to understand, while class components offer more power and flexibility. Both have their strengths and weaknesses, but with the rise of hooks, functional components are becoming the preferred choice for many developers.

Functional Component
React Class Component
Reactjs
React Hook
React Lifecycle
Recommended from ReadMedium