Published December 13, 2024

States and Props in React

States and Props are essential concepts for managing data and rendering components dynamically

image

In React, State is a local, mutable object used to manage dynamic data within a component, updated using useState or setState. Props, on the other hand, are immutable properties passed from a parent component to a child to make components reusable and dynamic. While state manages internal data, props handle data communication between components.

State and Props

  • Managing state with useState and passing data via props.
  • Understanding state immutability.

Managing State with useState and Passing Data via Props

In React, useState is a Hook that allows you to manage the state of a functional component. State is essentially data that can change over time and affect what gets rendered on the screen. useState returns an array containing two values: the current state and a function to update that state.

Props (short for properties) allow you to pass data from one component to another, typically from a parent component to a child component. Props are read-only and cannot be modified within the child component, making them a way to pass information down the component tree.

Example 1: Managing State with useState

<!doctype html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <link rel="icon" type="image/svg+xml" href="/vite.svg" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Vite + React</title>

  </head>

  <body>

    <div id="root"></div>

    <script type="module" src="/src/main.jsx"></script>

  </body>

</html>

Explanation

  • const [count, setCount] = useState(0) declares a state variable count initialized to 0.
  • The setCount function is used to update the count value.
  • Every time the "Increment" button is clicked, the increment function runs, calling setCount(count + 1), which updates the count.

Output

After clicking the button, the count will increase by 1.

Passing Data via Props

import React from 'react';

// Child component

function DisplayMessage({ message }) {

  return <h2>{message}</h2>;

}

// Parent component

function App() {

  const myMessage = "Hello from the parent component!";

  return (

    <div>

      <DisplayMessage message={myMessage} />

    </div>

  );

}

export default App;

Explanation

  • The App component declares a string myMessage.
  • It passes myMessage to the DisplayMessage component via the message prop.
  • In DisplayMessage, the prop is destructured and displayed using JSX.

Output

 


 

 Understanding State Immutability

State immutability means that the state should not be directly modified. Instead, a new state object or array should be created whenever the state is updated. This ensures that React can properly detect changes and re-render components efficiently.

Directly mutating the state can lead to unexpected behavior and bugs. This is because React relies on detecting differences between previous and current states (called "shallow comparison").

Example 2: Incorrect and Correct State Updates

Incorrect State Update (Direct Mutation)

import React, { useState } from 'react';

function IncorrectArrayUpdate() {

  const [items, setItems] = useState([1, 2, 3]);

  const addItem = () => {

    items.push(4); // Direct mutation (incorrect)

    setItems(items); // React might not re-render properly

  };

  return (

    <div>

      <ul>

        {items.map((item, index) => (

          <li key={index}>{item}</li>

        ))}

      </ul>

      <button onClick={addItem}>Add Item</button>

    </div>

  );

}

export default IncorrectArrayUpdate;

Explanation

Here, we are directly mutating the array items using items.push(4). React may not properly re-render the component because it doesn't detect that the state has changed.

Correct State Update (Immutability Preserved)

import React, { useState } from 'react';

function CorrectArrayUpdate() {

  const [items, setItems] = useState([1, 2, 3]);

  const addItem = () => {

    // Create a new array with the existing items and the new item

    setItems([...items, 4]);

  };

  return (

    <div>

      <ul>

        {items.map((item, index) => (

          <li key={index}>{item}</li>

        ))}

      </ul>

      <button onClick={addItem}>Add Item</button>

    </div>

  );

}

export default CorrectArrayUpdate;

Explanation

  • Instead of directly modifying the array, we create a new array using the spread operator ...items and add the new item (4).
  • This ensures immutability, allowing React to detect changes and re-render the component as needed.

Output

Before clicking "Add Item":

After clicking "Add Item":


Summary

  • useState allows you to manage state in functional components, while props enable passing data between components.
  • Immutability is crucial in state management to ensure React efficiently tracks and updates the UI when the state changes

___________________________________________________________________

Case Study 1: Shopping Cart App

Concept: Managing state with useState to add items to a cart, update item quantities, and display the total price.

Goal: Create a basic shopping cart app where users can add items, update quantities, and view the total price.

Components:

App: Main component that holds the state for cart items.

ProductList: Displays the list of products.

ProductItem: Represents a single product with an "Add to Cart" button.

Cart: Displays the added items, quantities, and total price.

App.jsx

import React, { useState } from 'react';

import ProductList from './ProductList';

import Cart from './Cart';

import './App.css';

const App = () => {

  const [cart, setCart] = useState([]);

  const addToCart = (product) => {

    const productExists = cart.find(item => item.id === product.id);

   if (productExists) {

      setCart(cart.map(item =>

        item.id === product.id

          ? { ...productExists, quantity: productExists.quantity + 1 }

          : item

      ));

    } else {

      setCart([...cart, { ...product, quantity: 1 }]);

    }

  };

  const updateQuantity = (productId, quantity) => {

    setCart(cart.map(item =>

      item.id === productId ? { ...item, quantity } : item

    ));

  };

  return (

    <div className="app">

      <h1>Shopping Cart App</h1>

      <ProductList addToCart={addToCart} />

      <Cart cart={cart} updateQuantity={updateQuantity} />

    </div>

  );

};

export default App;

ProductList.jsx

import React from 'react';

import ProductItem from './ProductItem';

const products = [

  { id: 1, name: 'Laptop', price: 1000 },

  { id: 2, name: 'Phone', price: 500 },

];

const ProductList = ({ addToCart }) => {

  return (

    <div className="product-list">

      {products.map(product => (

        <ProductItem key={product.id} product={product} addToCart={addToCart} />

      ))}

    </div>

  );

};

export default ProductList;

ProductItem.jsx

import React from 'react';

const ProductItem = ({ product, addToCart }) => {

  return (

    <div className="product-item">

      <h3>{product.name}</h3>

      <p>Price: ${product.price}</p>

      <button onClick={() => addToCart(product)}>Add to Cart</button>

    </div>

  );

};

export default ProductItem;

Cart.jsx

import React from 'react';

const Cart = ({ cart, updateQuantity }) => {

  const total = cart.reduce((acc, item) => acc + item.price * item.quantity, 0);

  return (

    <div className="cart">

      <h2>Cart</h2>

      {cart.map(item => (

        <div key={item.id} className="cart-item">

          <span>{item.name}</span>

          <span>

            Quantity:

            <input

              type="number"

              value={item.quantity}

              onChange={(e) => updateQuantity(item.id, Number(e.target.value))}

            />

          </span>

          <span>Price: ${item.price * item.quantity}</span>

        </div>

      ))}

      <h3>Total: ${total}</h3>

    </div>

  );

};

export default Cart;

App.css

.app {

  padding: 20px;

  text-align: center;

}

.product-list {

  display: flex;

  justify-content: space-around;

}

.product-item {

  border: 1px solid #ccc;

  padding: 20px;

  border-radius: 5px;

  margin: 10px;

}

.cart {

  margin-top: 20px;

}

.cart-item {

  display: flex;

  justify-content: space-between;

  margin-bottom: 10px;

}

How We Use States and Props Here:

State:

We use useState in the App component to manage the cart (cart state), which stores the items added by the user.

The state also keeps track of the quantity of each item.

setCart is used to update the cart state whenever a new item is added, quantity is changed, or an item is removed.

Props:

The addToCart function is passed as a prop from App to ProductList and then to each ProductItem.

The cart and updateQuantity functions are passed as props to the Cart component to display the items and update their quantities.

_______________________________________________________________

MCQs :-

1. What does the useState hook in React return?

A. An array with a single value.

B. A tuple with a value and a function to update the value.

C. An object with key-value pairs.

D. A promise.

Answer: B

Explanation: useState returns a tuple containing the current state and a function to update that state.

 

2. What is the correct syntax to use useState in a functional component?

A. const [state, setState] = useState(initialValue)

B. const state = useState(initialValue)

C. useState(state, setState)

D. const [state] = useState(initialValue)

Answer: A

Explanation: useState should be used as const [state, setState] to declare the state variable and the function to update it.

 

3. Which of the following is NOT a valid initial value for useState?

A. undefined

B. null

C. false

D. this

Answer: D

Explanation: this is not used in functional components. useState can take any JavaScript value as an initial state.

 

4. How do you update the state value in React using useState?

A. Directly modify the state variable.

B. Call the setter function returned by useState.

C. Use setState method like in class components.

D. Use the forceUpdate method.

Answer: B

Explanation: In functional components, the setter function (like setState) is used to update the state.

 

5. What happens if you directly modify a state variable instead of using its setter function?

A. The UI will still update.

B. The change will be ignored.

C. React will throw an error.

D. The state will be updated but the component won't re-render.

Answer: D

 

Download Lecture Pdf..

Reviews

Leave a Comment