Part 1: The Evolution of React: From Class Components to Hooks — The Beginnings

Sania Jamil
Aurora Solutions
Published in
6 min readAug 23, 2024

In the ever-evolving world of web development, React has been at the forefront of innovation, constantly adapting to meet the changing needs of developers. One of the most significant shifts in React’s evolution has been the transition from class components to hooks. This transition has revolutionized the way we manage state, handle side effects, and enhance the reusability of logic in React applications.

In this three-part blog series, we will explore the journey of React from its early days of class components to the introduction of hooks, diving into the advantages and benefits they bring to modern React development. In this part, we’ll discuss the beginnings of React, focusing on class components and their role in the framework’s early days. The second part will cover the transition period, highlighting the challenges that led to the introduction of hooks. In the last part, we will talk about the impact of hooks on modern development and how they have transformed the way we build dynamic and efficient user interfaces. We will uncover the power and flexibility of React Hooks and examine how they have reshaped the landscape of React development.

Overview of React’s Initial Release

React, introduced by Facebook in 2013, revolutionized the way developers build user interfaces for web applications. With its component-based architecture and virtual DOM (Document Object Model), React offered an efficient and declarative approach to building UIs.

React’s initial release brought several key advantages to the table. First and foremost, it allowed developers to break down complex UIs into smaller, reusable components. This modular approach not only improved code organization but also facilitated code reuse and maintenance.

Another notable feature of React was its virtual DOM. By leveraging a virtual representation of the actual DOM, React optimized the updating process, resulting in better performance and rendering speed. Instead of re-rendering the entire DOM tree, React only updated the necessary components, making UI updates highly efficient.

React’s popularity quickly spread within the developer community due to its simplicity and effectiveness. Its component-centric approach resonated well with developers, enabling them to build scalable and maintainable applications. The release of React laid the foundation for the subsequent evolution of the library, leading to the introduction of Hooks as a more flexible and intuitive way to develop React applications.

Class Components: The Starting Point

Class components played a fundamental role in the early days of React development. They served as the building blocks for creating dynamic and interactive user interfaces. In this section, we will explore the concept of class components and their significance in React.

A class component in React is a JavaScript class that extends the React.Component class. It encapsulates the logic and state of a specific component, allowing developers to define the behavior and appearance of their UI elements.

One of the key advantages of using class components is their ability to manage state. State represents the data that changes over time in a component, such as user input, API responses, or UI interactions. By utilizing the state object, developers could update and reflect changes in the UI dynamically.

To illustrate the concept of class components, let’s consider a simple example of a counter-component. The counter component will have a state property, “count,” which keeps track of the current count value. We can define the initial state in the component’s constructor and update it using the setState method.

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

render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
<button onClick={this.decrement}>Decrement</button>
</div>
);
}

increment = () => {
this.setState({ count: this.state.count + 1 });
};

decrement = () => {
this.setState({ count: this.state.count - 1 });
};
}

In the above example, the Counter component maintains its count state, which is initially set to 0. The render method displays the current count value, along with two buttons to increment and decrement the count. The increment and decrement methods update the state using the setState method, triggering a re-render of the component.

Class components also introduced lifecycle methods, which allow developers to hook into specific moments in a component’s lifecycle. These methods include componentDidMount, componentDidUpdate, and componentWillUnmount, among others. They provide opportunities to perform actions such as fetching data from an API, setting up event listeners, or cleaning up resources when the component is unmounted.

While class components served as a solid foundation for building React applications, they did come with some challenges. As applications grew in complexity, managing state and handling side effects became more cumbersome. The need for a simpler and more flexible approach led to the introduction of Hooks, which we will explore in the subsequent sections.

The Beginnings of React

React, created by Facebook, was first introduced in 2013 as a JavaScript library for building user interfaces. It quickly gained popularity due to its unique approach to component-based development and its focus on efficiency and performance.

At its inception, React primarily relied on class components as the fundamental building blocks for UI development. Class components allowed developers to manage state, handle lifecycle methods, and build reusable UI components.

Class components provided a structured way to organize and manage state within a component, making it easier to maintain and update the UI based on changes in data. However, as React applications grew in complexity, class components started to show limitations and boilerplate code, leading to a need for a more streamlined and efficient approach.

State and Lifecycle Methods

State management is a crucial aspect of building dynamic and interactive user interfaces. In React’s early days, class components played a pivotal role in managing state and handling lifecycle methods.

Managing state with class components

Class components in React provide a built-in mechanism for managing and updating state. The state object allowed developers to store and modify data within a component. By using the setState() method, changes to the state would trigger a re-render of the component, updating the UI accordingly.

The ability to manage state within a component was a significant advantage of class components. It enabled developers to create interactive and responsive interfaces by dynamically updating the UI based on changes in data.

Common lifecycle methods

Lifecycle methods in class components allowed developers to perform specific actions at different stages of a component’s lifecycle. These methods included:

componentDidMount: Invoked after the component has been rendered for the first time. It is commonly used for fetching data from an API or setting up event listeners.

componentDidUpdate: Called after a component’s state or props have changed, and the component is re-rendered. This method is often used to update the UI based on changes in data.

componentWillUnmount: Called right before a component is removed from the DOM. It provides an opportunity to clean up any resources or event listeners associated with the component.

These lifecycle methods allowed developers to incorporate additional logic and behavior into their components at specific points in their lifecycle, enhancing the functionality and interactivity of the UI.

Managing Side Effects

In addition to managing state and handling lifecycle methods, React class components also provided a way to deal with side effects. Side effects are actions or operations that occur outside the scope of the component, such as API calls, DOM manipulations, or subscriptions.

Approach to side effects in class components

In class components, side effects were typically handled within lifecycle methods like componentDidMount and componentDidUpdate. These methods allowed developers to execute side effect logic when the component mounted or when specific props or state changed.

However, managing side effects within lifecycle methods often led to verbose and scattered code. As applications grew in complexity, it became challenging to keep track of all the side effects and ensure they were properly cleaned up when the component unmounted.

Conclusion

As we’ve explored in this first part, class components played a crucial role in the early days of React, providing a solid foundation for managing state and handling lifecycle methods. However, as applications grew in complexity, the challenges of managing state and side effects became increasingly apparent, paving the way for a more streamlined approach.

In the next part of this series, we’ll dive into the transition period, highlighting the challenges that led to the introduction of hooks. We’ll explore how Hooks addressed the limitations of class components and why they became a game-changer for modern React development. Stay tuned!

--

--