React Function vs Class Components Explained

4 min read
Cover Image for React Function vs Class Components Explained

Function VS Class

In the world of React development, components are the building blocks of every user interface. Traditionally, developers used Class Components to manage state and lifecycle methods, but with the introduction of Hooks, Function Components have become the preferred approach for many. They offer cleaner syntax, improved readability, and easier state management without the need for boilerplate code. This article explores the key differences between Function and Class Components, helping developers understand when and why to use each approach.

Function Component

The useState hook in React is a powerful feature that allows function components to manage internal state without relying on class-based syntax. It returns a state variable and a function to update that state, enabling dynamic behavior and reactivity within components. For example, you can track user input, toggle UI elements, or update counters—all with just a few lines of code. This simplicity and flexibility make useState one of the most commonly used hooks in modern React development.

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
};

Class Component

In React Class Components, setState is the method used to update a component’s state and trigger re-rendering. While it’s effective for managing dynamic data, using setState often requires more boilerplate code—such as defining constructors, binding methods, and handling lifecycle events manually. Compared to the concise syntax of useState in Function Components, working with setState can feel more complex and verbose, especially when managing multiple state values or reacting to updates. This added length and structure make Class Components less favored in modern React development.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleIncrease = () => {
    this.setState((prevState) => ({
      count: prevState.count + 1,
    }));
  };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleIncrease}>Increase</button>
      </div>
    );
  }
}

useEffect

The useEffect hook in React is used to handle side effects in Function Components, such as fetching data, setting up subscriptions, or interacting with the DOM. It runs after the component renders and can be customized to run only once, on every update, or when specific values change—depending on the dependencies provided. This hook helps keep your code organized and reactive, making it easier to manage external interactions within your component logic.

Before useEffect

Before the introduction of the useEffect hook in React Function Components, Class Components relied on built-in lifecycle methods to handle side effects such as data fetching, subscriptions, and DOM updates. Developers used componentDidMount to run code after the component was first rendered, componentDidUpdate to respond to state or prop changes, and componentWillUnmount for cleanup tasks like clearing timers or removing event listeners. While effective, these methods often required more verbose and structured code, making Function Components with useEffect a simpler and more flexible alternative in modern React development.

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  // useEffect(() => { ... }, [])
  componentDidMount() {
    console.log("Timer mounted");
    this.interval = setInterval(() => {
      this.setState((prev) => ({ count: prev.count + 1 }));
    }, 1000);
  }

  // useEffect(() => { ... }, [count])
  componentDidUpdate(prevProps, prevState) {
    if (prevState.count !== this.state.count) {
      console.log("Count berubah:", this.state.count);
    }
  }

  // cleanup function in useEffect
  componentWillUnmount() {
    console.log("Timer akan dihapus");
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>
        <h2>Waktu berjalan: {this.state.count} detik</h2>
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { showTimer: true };
  }

  toggleTimer = () => {
    this.setState((prev) => ({ showTimer: !prev.showTimer }));
  };

  render() {
    return (
      <div>
        <button onClick={this.toggleTimer}>Toggle Timer</button>
        {this.state.showTimer && <Timer />}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

Conclusion

In conclusion, understanding the differences between Function and Class Components in React is essential for writing clean, efficient, and modern code. With the advent of Hooks like useState and useEffect, Function Components have become the preferred choice due to their simplicity, reduced boilerplate, and improved readability. While Class Components still offer robust features through methods like setState and lifecycle hooks, they often require more verbose syntax and structure. By embracing Function Components, developers can streamline their workflow and build reactive interfaces with greater ease.