Understanding React Components with Examples
Introduction:
React, a JavaScript library for building user interfaces, has gained widespread popularity due to its component-based architecture that promotes reusability and modularity. Central to this architecture are components and props. In this article, we will delve into the fundamental concepts of React components and explore how props facilitate dynamic data flow within these components.
An Introduction to React Components
React components are the building blocks of a user interface. They encapsulate a piece of the UI, making it reusable and self-contained. Components can be thought of as Lego blocks that you can assemble to construct a complex application. There are two main types of components: functional components and class components.
Types of React Components
React provides developers with a range of component types, each tailored for specific use cases and scenarios. In this section, we’ll delve into the various types of React components, discussing their characteristics, benefits, and when to use them.
React Functional Components
React functional components are a fundamental building block in React applications. They are JavaScript functions that return JSX (JavaScript XML) to define the UI. Functional components are a concise and straightforward way to create reusable UI elements in React. They have become more popular over time due to their simplicity and improved performance.
Here are some key features of React functional components:
Simplicity: Functional components are simpler and easier to read compared to class components. They don’t require dealing with the complexities of class-based syntax, state, and lifecycle methods.
No State: By default, functional components don’t have state. They are primarily used for presenting UI elements and don’t manage internal state like class components do.
Props: Functional components can accept props as parameters. Props are data that is passed from parent to child components, allowing the component to be customized and dynamic.
Hooks: With the introduction of React Hooks, functional components gained the ability to manage state and use lifecycle-like features. Hooks like useState, useEffect, and more enable functional components to have stateful behavior.
Performance: Functional components are generally more performant than class components because they have a simpler internal representation in the React codebase.
React Functional Components Examples:
Example 1: Basic Functional Component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import React from 'react'; // Functional component const Greeting = () => { return <h1>Hello, React Functional Component!</h1>; }; export default Greeting; |
In this example, we’ve created a simple functional component called Greeting that renders an <h1> element with a greeting message. This component doesn’t accept any props and doesn’t have any state or lifecycle methods.
Example 2: Functional Component with Props
Welcome js file Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //Welcome.js file import React from 'react'; // Functional component with props const Welcome = (props) => { return <h1>Welcome, {props.name}!</h1>; }; export default Welcome; |
In this example, the Welcome functional component accepts a prop called name and displays a personalized welcome message. You can use this component like this:
App js file code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //App.js file import React from 'react'; import Welcome from './Welcome'; // Make sure to import the component correctly const App = () => { return <Welcome name="Programming Digest" />; }; export default App; |
Example 3: Functional Component with Destructuring Props
UserInfo js file 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 | //UserInfo.js file import React from 'react'; // Functional component with destructuring props const UserInfo = ({ username, age }) => { return ( <div> <p>Username: {username}</p> <p>Age: {age}</p> </div> ); }; export default UserInfo; |
App js file 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 | //App.js file import React from 'react'; import UserInfo from './UserInfo'; // Make sure to adjust the import path const App = () => { return ( <div> <h1>User Information</h1> <UserInfo username="Fawad khan" age={28} /> </div> ); }; export default App; |
In this example, the UserInfo functional component uses object destructuring to directly extract username and age from the props object. This makes the code more concise and readable.
Remember that functional components are a great choice for simple UI elements, but for more complex components that require state management or lifecycle methods, you might want to explore class components or React hooks.
You can create these components in separate .js files and import and use them in your main application file. Make sure you have React properly set up in your project to use these components.
Class Components
Class components were the original way of creating components in React before the introduction of functional components and hooks. They are ES6 classes that extend the React.Component class provided by the React library. Class components offer more advanced features like state management and lifecycle methods, making them suitable for complex UI elements that require internal state or interactions with the component lifecycle.
Class Components Examples:
Example 1: Basic Class Component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import React from 'react'; // Class component class Greeting extends React.Component { render() { return <h1>Hello, Class Component!</h1>; } } export default Greeting; |
In this example, Greeting is a basic class component that renders a greeting message using the render() method. Class components have a render() method that returns JSX to define the component’s UI.
Example 2: Class Component with State
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 44 45 46 47 48 49 50 51 | import React from 'react'; // Class component with state class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.increment}>Increment</button> </div> ); } } export default Counter; |
In this example, Counter is a class component that uses the state object to keep track of a count value. The increment method updates the count when the button is clicked.
Example 3: Interactive Timer with 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | import React from 'react'; class Timer extends React.Component { constructor(props) { super(props); this.state = { seconds: 0, running: false }; this.timerInterval = null; } startTimer = () => { this.setState({ running: true }); this.timerInterval = setInterval(() => { this.setState((prevState) => ({ seconds: prevState.seconds + 1 })); }, 1000); }; stopTimer = () => { this.setState({ running: false }); clearInterval(this.timerInterval); }; resetTimer = () => { this.setState({ seconds: 0, running: false }); clearInterval(this.timerInterval); }; componentWillUnmount() { clearInterval(this.timerInterval); } render() { return ( <div> <h2>Timer: {this.state.seconds} seconds</h2> <button onClick={this.state.running ? this.stopTimer : this.startTimer}> {this.state.running ? 'Stop' : 'Start'} </button> <button onClick={this.resetTimer}>Reset</button> </div> ); } } export default Timer; |
The provided code defines a React class component named Timer. This component represents a timer that counts the number of seconds elapsed and allows the user to control its behavior through buttons.
Initially, the component’s state is set with seconds initialized to 0 and running set to false. Additionally, a variable timerInterval is set to null.
The class methods within the component include:
startTimer: This method starts the timer by setting the running state to true and initiating an interval that increments the seconds state by 1 every 1000 milliseconds (1 second).
stopTimer: This method stops the timer by setting the running state to false and clearing the interval using clearInterval.
resetTimer: This method resets the timer by setting seconds back to 0 and running to false, and also clearing the interval.
componentWillUnmount: This lifecycle method ensures that the interval is cleared when the component is about to be unmounted, preventing memory leaks.
In the render method, the component displays the current number of seconds in a heading element. Two buttons are provided: one for starting/stopping the timer and another for resetting it. The button text dynamically changes based on whether the timer is running or stopped.
Note:
While class components are still valid and functional, React’s focus has shifted towards functional components and hooks due to their simplicity and improved performance. Many features that were previously only available in class components, like state and lifecycle methods, can now be achieved using hooks with functional components.
Keep in mind that functional components and hooks are the recommended approach for new React projects, but existing projects may still have class components.
In all examples above, you can create these components in separate .js files, import them, and use them in your application as needed.
Pure Components
Pure Components are a specific type of React component that automatically performs a shallow comparison of the current props and state with the next props and state. If there are no changes, a pure component prevents unnecessary re-rendering, which can help improve performance in certain cases.
Pure Components extend the React.PureComponent class provided by React. This class implements the shouldComponentUpdate lifecycle method with a shallow comparison, so you don’t have to manually implement it for each component.
Pure components Examples:
Example 1: Basic Pure Component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import React from 'react'; class PureGreeting extends React.PureComponent { render() { return <h1>Hello, Pure Component!</h1>; } } export default PureGreeting; |
in this example, PureGreeting is a basic pure component that renders a greeting message. Since there are no props or state changes, this component won’t re-render unnecessarily.
Example 2: Pure Component with Props
App js file 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 | //App.js file import React from 'react'; import PureUserProfile from './PureUserProfile '; const App = () => { return ( <div> <h1>User Information</h1> <PureUserProfile username="Fawad Khan" age={28} /> </div> ); }; export default App; |
PureUserProfile js file 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 | //PureUserProfile.js file import React from 'react'; class PureUserProfile extends React.PureComponent { render() { return ( <div> <p>Username: {this.props.username}</p> <p>Age: {this.props.age}</p> </div> ); } } export default PureUserProfile; |
In this example, PureUserProfile is a pure component that displays user profile information based on props. If the props remain the same between updates, this component won’t re-render.
Example 3: Optimizing List Rendering with Pure Component
App js file 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 43 44 45 46 47 48 49 50 51 52 | //App.js file import React from 'react'; import UserList from './UserList'; class App extends React.Component { state = { users: [ { id: 1, name: 'Fawad Khan' }, { id: 2, name: 'Engr Fahad' }, { id: 3, name: 'Farrukh' }, ], }; render() { const { users } = this.state; return ( <div> <h1>User Management</h1> <UserList users={users} /> </div> ); } } export default App; |
UserList js file 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 | //UserList.js file import React from 'react'; class UserList extends React.PureComponent { render() { const { users } = this.props; return ( <div> <h2>User List</h2> <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> </div> ); } } export default UserList; |
In this example, UserList is a pure component that renders a list of users. If the users prop remains unchanged between updates, this component won’t re-render. This can be particularly useful for optimizing list rendering.
Higher-Order Components (HOCs)
A Higher-Order Component (HOC) is a design pattern in React that enhances the functionality of components by wrapping them with another component. HOCs are not a feature provided by React itself, but rather a pattern that leverages the composability of components. They allow you to reuse component logic, add additional props, modify behavior, and more without modifying the original component’s code.
In essence, a Higher-Order Component is a function that takes a component as an argument and returns a new component with added features or behavior.
Higher-Order Components Examples:
Example 1: HOC for adding a loading spinner to a 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | import React, { Component } from 'react'; // Higher-Order Component const withLoading = (WrappedComponent) => { return class WithLoading extends Component { render() { const { isLoading, ...props } = this.props; if (isLoading) { return <div>Loading...</div>; } return <WrappedComponent {...props} />; } }; }; // Component to be wrapped const MyComponent = ({ data }) => ( <ul> {data.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> ); // Wrap the component with the HOC const MyComponentWithLoading = withLoading(MyComponent); // Usage const data = [ { id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }, // ... ]; function App() { return ( <div> <h1>My App</h1> <MyComponentWithLoading isLoading={false} data={data} /> </div> ); } export default App; |
This code is a demonstration of a Higher-Order Component (HOC) pattern in React. The code begins by importing the necessary modules from the React library. It defines a HOC named withLoading, which takes a WrappedComponent as an argument. This HOC is designed to enhance a component by providing loading functionality. Inside the withLoading function, a new class called WithLoading is created, extending the React Component class. Within this class, a render method is defined. This method checks if the isLoading prop is true; if it is, a “Loading…” message is displayed; otherwise, the original WrappedComponent is rendered with all its props.
The code also defines a simple functional component named MyComponent, which renders a list of items based on the data prop. Then, it uses the withLoading HOC to wrap the MyComponent, resulting in a new component called MyComponentWithLoading.
Finally, a functional component named App is defined. Inside it, an array of data is created, representing a list of items. The App component renders a title and then uses the MyComponentWithLoading component, passing it the isLoading prop set to false and the data prop with the prepared array. When the App component is used, it displays the title and the MyComponent enhanced with loading functionality through the HOC, showing the list of items or a loading message based on the isLoading prop.
Example 2: HOC for adding authentication to a 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | import React, { Component } from 'react'; // Simulated authentication status const isAuthenticated = true; // Higher-Order Component const withAuth = (WrappedComponent) => { return class WithAuth extends Component { render() { if (isAuthenticated) { return <WrappedComponent {...this.props} />; } else { return <div>You need to be authenticated to view this content.</div>; } } }; }; // Component to be wrapped const AuthenticatedComponent = () => ( <div> <h2>Welcome to the authenticated area!</h2> <p>This content is only visible to authenticated users.</p> </div> ); // Wrap the component with the HOC const AuthenticatedComponentWithAuth = withAuth(AuthenticatedComponent); // Usage function App() { return ( <div> <h1>My App</h1> <AuthenticatedComponentWithAuth /> </div> ); } export default App; |
This code exemplifies the use of a Higher-Order Component (HOC) pattern in a React application to implement an authentication feature. The code starts by importing the necessary modules from the React library. It then sets up a simulated authentication status, represented by the isAuthenticated variable, which is initially set to true to simulate an authenticated state.
The code defines a HOC named withAuth, which takes a WrappedComponent as an argument. Inside the withAuth function, a new class named WithAuth is created by extending the React Component class. Within this class, a render method is defined. Inside the render method, it checks the isAuthenticated status. If the user is authenticated (isAuthenticated is true), it renders the WrappedComponent passed to the HOC with all the props intact. If the user is not authenticated, it displays a message indicating that authentication is required to access the content.
The code also defines a simple functional component named AuthenticatedComponent, which represents content intended for authenticated users. It includes a title and a paragraph indicating that the content is only visible to authenticated users.
The HOC withAuth is used to wrap the AuthenticatedComponent, creating a new component named AuthenticatedComponentWithAuth.
Lastly, the code defines a functional component named App, which renders a title and then uses the AuthenticatedComponentWithAuth component. When the App component is used, it displays the title and the content of the AuthenticatedComponent if the user is authenticated or a message prompting authentication if the user is not authenticated.