In this article, we will learn about the uses of shouldComponentUpdate() method in class-based components. The shouldComponentUpdate() life cycle method does not run for the initial render but for every re-render after the initial render. It is invoked before the component re-renders when the updated props or state are being received in the component. Also, its default value is true. We can change the default value by overwriting it with the help of some conditional JSX. Its major use case is in optimizing the react web app. It can be used to avoid unnecessary re-rendering of react components. Let’s understand it with an example.
Creating React Application And Installing Module:
Step 1: Create a React application using the following command.
npx create-react-app foldername
Step 2: After creating your project folder i.e. foldername, move to it using the following command:
cd foldername
Step 3: Run the development server by using the following command:
npm start
Project Structure: It will look like the following.
Implementation: Add codes in respective files.
App.js: In this component we have created a neveropenCourses array containing data for courses available, a state termed as cart with the help of useState() hook, applied some basic styles. Also passed down props with their respective names.
Javascript
import { useState } from "react" ; import "./App.css" ; import Cart from "./Components/Cart" ; import Courses from "./Components/Courses" ; function App() { let geekCourses = [ { title: "App development with Java and Kotlin" , price: 10000, duration: 5, mentor: "Aman Negi" , TA: "Rahul Negi" , classesPerWeek: 5, }, { title: "Web development Nodejs" , price: 9000, duration: 4, mentor: "Riya Rawat" , TA: "Mihir Rawat" , classesPerWeek: 4, }, { title: "MERN stack " , price: 12000, duration: 6, mentor: "Kartik Sayana" , TA: "Amogh Sayana" , classesPerWeek: 6, }, { title: "Machine Learning with python" , price: 10000, duration: 6, mentor: "Rohit Jain" , TA: "Utkarsh Jain" , classesPerWeek: "5" , }, ]; const [cart, setCart] = useState({}); return ( <> <div style={{ width: "50%" , margin: "auto" , textAlign: "center" }}> <h2>Geeks Courses</h2> </div> <div style={{ display: "flex" , alignItems: "center" }}> <Courses geekCourses={geekCourses} setCart={setCart} cart={cart} /> <Cart cart={cart} /> </div> </> ); } export default App; |
Courses.js : In this component, we have added basic styles, destructured geekCourses, and setCart property from props. Hooked up an onClick handler to every course JSX in the geekCourses array, which when clicked will update the cart of the user.
Javascript
import React from "react" ; import PropTypes from "prop-types" ; const Courses = ({ geekCourses, setCart }) => { let displayCourses = geekCourses.map((course, idx) => { return ( <div key={idx} style={{ border: "2px solid rgb(91, 222, 115)" , margin: "5px" , width: "20vw" , borderRadius: "10px" , boxShadow: "5px 3px 11px -1px rgba(0,0,0,0.46)" , padding: "5px" , }} > <h3> {course.title} </h3> <div style={{ display: "flex" , justifyContent: "space-between" , alignItems: "center" , }} > <span style={{ margin: "5px" }}> <strong>Duration:</strong> {course.duration} days </span> <span style={{ margin: "5px" }}> <strong>Price:</strong> {course.price} Rs </span> </div> <div style={{ display: "flex" , justifyContent: "space-between" , alignItems: "center" , margin: "10px 5px" , }} > <span style={{ margin: "5px" }}> <strong>Mentor:</strong> {course.mentor} </span> <span style={{ margin: "5px" }}> <strong>TA:</strong> {course.TA} </span> </div> <div style={{ display: "flex" , justifyContent: "space-around" , alignItems: "center" , }} > <button style={{ padding: "2px 15px" , borderRadius: "10px" , border: "none" , backgroundColor: "rgb(3, 252, 86)" , fontWeight: "bold" , cursor: "pointer" , }} onClick={() => { let newCart = { title: course.title, mentor: course.mentor, price: course.price, }; setCart(newCart); }} > BUY </button> </div> </div> ); }); return ( <> <div style={{ width: "60vw" }}> <div style={{ display: "flex" , flexWrap: "wrap" , padding: "5px" , justifyContent: "center" , }} > {displayCourses} </div> </div> </> ); }; export default Courses; |
Cart.js: This component shows the actual use-case of shouldComponentUpdate() method. As we know this method has two arguments which are nextProps and nextState. In this method, we have added conditional logic to return true or false based on the comparison between the title of nextProps and the current cart’s title. This comparison is a naive comparison and not recommended for larger applications, in complex applications we can use the property which differentiates any two courses or objects to do the comparison and return whether or not the component should be updated. This method’s return value determines whether or not the component will update. We have also used a conditional operator that when the object is initially empty ( the length of keys of the object is zero ) then we will display some data else we will display the cart.
Javascript
import React, { Component } from "react" ; export class Cart extends Component { shouldComponentUpdate(nextProps, nextState) { const { cart } = this .props; console.log( "nextProps" , nextProps.cart); if (Object.keys(cart).length === 0) return true ; return nextProps.cart.title !== this .props.cart.title; } render() { console.log( "rendering Cart Component" ); const { cart } = this .props; let cartData = ( <> <div style={{ display: "flex" , justifyContent: "space-between" }}> <h4>{cart.title}</h4> <h5> {cart.mentor} </h5> </div> <div style={{ display: "flex" , justifyContent: "space-between" }}> <strong>{cart.price}</strong> <button style={{ padding: "2px 15px" , borderRadius: "10px" , border: "none" , backgroundColor: "rgb(3, 252, 86)" , fontWeight: "bold" , cursor: "pointer" , }} > CHECKOUT </button> </div> </> ); return ( <div style={{ width: "35vw" , height: "150px" , border: "3px solid rgb(3, 252, 82)" , borderRadius: "10px" , padding: "10px" , margin: "5px" , }} > {Object.keys(cart).length === 0 ? ( <h3>Your cart is empty</h3> ) : ( <> <h3 style={{ margin: "2px" }}> Your-Cart </h3> {cartData} </> )} </div> ); } } export default Cart; |
Output:
On initial render: Note the console log.
On first click: We can see in the console that when we click on the first course to add it into the cart, the Cart component re-renders.
On second click: Note the console log again. This time the Cart component does not re-render because the state did not have any changes. i.e. the previous state had the App development course in the cart and after clicking it add the same course. So the shouldComponentUpdate() method returned false thereby not re-rendering the Cart component and optimizing web-apps performance.
Working demo of web-app: