React ES6 Classes, Methods and inheritance with Examples
Introduction:
React, a popular JavaScript library for building user interfaces, provides developers with multiple ways to create components. One of these ways is through ES6 classes, which offer a structured and organized approach to building reusable UI elements. In this article, we’ll delve into the key concepts of React ES6 classes, including classes themselves, methods within classes, and class inheritance, all supported by illustrative examples.
Classes in React:
React ES6 classes are a modern way of defining object-oriented structures in JavaScript. In React, components can be created using classes, allowing for a more organized and encapsulated development process. The class keyword is used to define a new class, and the extends keyword is used for inheritance.
In React, classes are a way to define components using ES6 class syntax. Components are the building blocks of a React application, representing reusable and self-contained units of UI.
In a class-based component, you define its behavior through methods such as render(), componentDidMount(), componentDidUpdate(), and more. The render() method is essential and returns the JSX (JavaScript XML) that describes the component’s UI structure.
State management is a key feature of class-based components. Components can hold their own local state using the state object. When state changes, the component automatically re-renders to reflect those changes in the UI. You can modify state using the setState() method, triggering a re-render.
Class-based components also support lifecycle methods. These methods allow you to control the behavior of your component at different stages of its life, such as when it’s created, updated, or unmounted from the DOM.
However, with the introduction of React Hooks, which are functions that provide a simpler and more flexible way to manage state and lifecycle in functional components, the usage of class-based components has become less common. Hooks like useState, useEffect, and useContext allow functional components to achieve the same functionalities as class-based components, but with a more concise and modular approach.
Example 1: Basic Class Component
1 2 3 4 5 6 7 8 9 10 11 12 13 | import React, { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, React!</h1>; } } export default Greeting; |
Example 2: Stateful Class Component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | import React, { Component } from 'react'; class Counter extends 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> ); } } export default Counter; |
Example 3: Class Component with Props
UserProfile.js Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import React, { Component } from 'react'; class UserProfile extends Component { render() { const { username, age } = this.props; return ( <div> <p>Username: {username}</p> <p>Age: {age}</p> </div> ); } } export default UserProfile; |
App.js Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import React, { Component } from 'react'; import UserProfile from './UserProfile'; // Import the UserProfile component class App extends Component { render() { return ( <div> <h1>User Profile App</h1> <UserProfile username="Fawad Khan" age={28} /> {/* Use UserProfile component with props */} </div> ); } } export default App; |
Methods in Classes:
Methods within React class components are functions that can be defined within the class to handle different behaviors and actions. These methods are often used to respond to user interactions, manage component state, and manipulate data.
In object-oriented programming, classes are blueprints for creating objects with specific properties and behaviors. Methods are functions defined within a class that encapsulate behaviors or actions associated with the objects created from that class. These methods allow objects to interact with each other and their environment.
Methods in classes serve several purposes:
Encapsulation: Methods encapsulate related functionality within the class, promoting clean code organization and separation of concerns. This makes it easier to manage and maintain the codebase.
Abstraction: Methods abstract the complex internal workings of an object, exposing only the necessary interface to the outside world. This promotes a clearer understanding of how to interact with the object.
Reusability: By defining methods within a class, you can reuse the same set of behaviors across multiple instances of that class. This reduces code duplication and promotes modular design.
Inheritance: Inheritance allows a class to inherit methods from a parent class, enabling the creation of specialized classes that inherit and extend behaviors from a base class. This supports the “is-a” relationship between classes.
Polymorphism: Polymorphism allows different classes to implement the same method names but with different implementations. This promotes code flexibility and supports diverse behaviors across different objects.
Functionality: Methods can interact with the object’s properties (attributes) and other methods to perform specific tasks, modify state, or provide information about the object’s state.
Methods can have varying levels of access based on access modifiers like public, private, and protected. Public methods are accessible from outside the class, private methods are only accessible within the class, and protected methods are accessible within the class and its subclasses.
When calling a method on an object, it can alter the object’s state or perform actions relevant to the object’s purpose. This promotes a structured approach to managing data and functionality, enhancing the overall design and maintainability of the code.
methods in classes encapsulate behaviors, interactions, and actions related to objects. They contribute to the principles of encapsulation, abstraction, reusability, inheritance, and polymorphism, all of which collectively lead to well-organized, modular, and maintainable code in object-oriented programming.
Example 1: Handling Click Events
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import React, { Component } from 'react'; class ClickCounter extends Component { constructor(props) { super(props); this.state = { count: 0 }; } handleIncrement = () => { this.setState({ count: this.state.count + 1 }); } render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.handleIncrement}>Increment</button> </div> ); } } export default ClickCounter; |
Example 2: Conditional Rendering
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import React, { Component } from 'react'; class ConditionalDisplay extends Component { constructor(props) { super(props); this.state = { showContent: false }; } toggleContent = () => { this.setState({ showContent: !this.state.showContent }); } render() { return ( <div> <button onClick={this.toggleContent}>Toggle Content</button> {this.state.showContent && <p>Content is visible now.</p>} </div> ); } } export default ConditionalDisplay; |
When clicked the button it will show the hidden content
Class Inheritance in React:
Inheritance is a fundamental concept in object-oriented programming that allows one class to inherit properties and methods from another class. In React, class components can be extended to create new components with shared functionalities.
Class inheritance in React allows you to create new components that inherit properties and behaviors from existing components. In object-oriented programming terms, it’s a mechanism by which a class (subclass or derived class) can extend the properties and methods of another class (superclass or base class). React’s class-based components use inheritance to promote code reuse, maintainability, and a structured approach to building UIs.
Inheritance works as follows:
Base Class (Superclass): In React, the base class is typically the React.Component class. This class defines the basic structure and behavior of a component, such as lifecycle methods, state management, and the rendering logic.
Derived Class (Subclass): The derived class is your custom component that extends the base class. It inherits all the properties and methods of the base class while allowing you to add or override specific behaviors to customize the component’s functionality.
Extending Behavior: By inheriting from the base class, the derived class inherits its methods, lifecycle hooks, and state management capabilities. You can leverage these inherited features to build upon the existing functionality and tailor it to your component’s specific requirements.
Overriding Methods: If needed, you can override methods from the base class in the derived class. This allows you to provide custom implementations for lifecycle methods or other behaviors, while still retaining the core features inherited from the base class.
Code Reusability: Inheritance facilitates code reuse, as you can create a base component with common functionality and then extend it to create specialized components. This promotes modular design and reduces code duplication.
Single Inheritance Limitation: React supports single inheritance, which means a component can only inherit from one base class. This limitation encourages developers to favor composition over deep inheritance hierarchies.
Example 1: Base and Derived Components
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import React, { Component } from 'react'; class BaseComponent extends Component { render() { return <p>This is the base component.</p>; } } class DerivedComponent extends BaseComponent { render() { return ( <div> {super.render()} <p>This is the derived component.</p> </div> ); } } export default DerivedComponent; |
Example 2: Adding Functionality through Inheritance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import React, { Component } from 'react'; class ButtonComponent extends Component { handleClick() { alert('Button Clicked!'); } } class EnhancedButton extends ButtonComponent { render() { return ( <button onClick={this.handleClick}>Click me</button> ); } } export default EnhancedButton; |
Example 3: Combining Inheritance with Props
DerivedForm.js Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import React, { Component } from 'react'; class BaseForm extends Component { handleSubmit(event) { event.preventDefault(); console.log('Form submitted'); } } class DerivedForm extends BaseForm { render() { return ( <form onSubmit={this.handleSubmit}> <button type="submit">Submit</button> </form> ); } } export default DerivedForm; |
App.js Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import React, { Component } from 'react'; import DerivedForm from './DerivedForm'; // Import the DerivedForm component class App extends Component { render() { return ( <div> <h1>Form App</h1> <DerivedForm /> {/* Use the DerivedForm component */} </div> ); } } export default App; |
Conclusion:
React ES6 classes offer a structured way to create components, define methods for handling behaviors, and achieve class inheritance for code reuse and extensibility. By understanding and applying these concepts, developers can build robust and maintainable UI components that cater to various requirements and user interactions. Through examples illustrating class creation, method utilization, and class inheritance, developers can better grasp the power of React ES6 classes in building modern, interactive user interfaces.