Skip to main content
Course/Module 1/Topic 4 of 5Intermediate

Props and State

Master React's data flow with props and state management

90 minBy Priygop TeamLast updated: Feb 2026

What are Props?

Props (properties) are a way to pass data from parent to child components. They are read-only and help make components reusable and configurable.

Props Examples

Example
// Passing props to component
function Welcome(props) {
    return <h1>Hello, {props.name}!</h1>;
}

// Using the component
<Welcome name="John" />

// Destructuring props
function Welcome({ name, age, city }) {
    return (
        <div>
            <h1>Hello, {name}!</h1>
            <p>Age: {age}</p>
            <p>City: {city}</p>
        </div>
    );
}

// Using with destructured props
<Welcome name="John" age={25} city="New York" />

// Props with children
function Container({ children }) {
    return <div className="container">{children}</div>;
}

<Container>
    <h1>This is a child</h1>
    <p>This is another child</p>
</Container>

State Management

Example
// Using useState hook (Function Component)
import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);
    
    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>
                Increment
            </button>
            <button onClick={() => setCount(count - 1)}>
                Decrement
            </button>
        </div>
    );
}

// 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 });
    }
    
    decrement = () => {
        this.setState({ count: this.state.count - 1 });
    }
    
    render() {
        return (
            <div>
                <p>Count: {this.state.count}</p>
                <button onClick={this.increment}>Increment</button>
                <button onClick={this.decrement}>Decrement</button>
            </div>
        );
    }
}

Props vs State

  • Props are read-only and passed from parent to child
  • State is mutable and managed within the component
  • Props trigger re-renders when parent updates them
  • State triggers re-renders when setState is called
  • Props are used for configuration and data flow
  • State is used for component-specific data

Advanced Props Patterns

Example
// Props with default values
function Button({ 
    children, 
    variant = 'primary', 
    size = 'medium',
    disabled = false,
    onClick 
}) {
    const className = `btn btn-${variant} btn-${size}`;
    
    return (
        <button 
            className={className}
            disabled={disabled}
            onClick={onClick}
        >
            {children}
        </button>
    );
}

// Props validation with PropTypes
import PropTypes from 'prop-types';

function UserCard({ user, onEdit, onDelete }) {
    return (
        <div className="user-card">
            <h3>{user.name}</h3>
            <p>{user.email}</p>
            <div className="actions">
                <button onClick={() => onEdit(user.id)}>Edit</button>
                <button onClick={() => onDelete(user.id)}>Delete</button>
            </div>
        </div>
    );
}

UserCard.propTypes = {
    user: PropTypes.shape({
        id: PropTypes.number.isRequired,
        name: PropTypes.string.isRequired,
        email: PropTypes.string.isRequired
    }).isRequired,
    onEdit: PropTypes.func.isRequired,
    onDelete: PropTypes.func.isRequired
};

// Props spreading
function FormField({ label, ...inputProps }) {
    return (
        <div className="form-field">
            <label>{label}</label>
            <input {...inputProps} />
        </div>
    );
}

// Usage
<FormField 
    label="Email"
    type="email"
    placeholder="Enter your email"
    required
/>

Advanced State Management

Example
// Complex state with objects
function UserProfile() {
    const [user, setUser] = useState({
        name: '',
        email: '',
        preferences: {
            theme: 'light',
            notifications: true
        }
    });

    const updateUser = (field, value) => {
        setUser(prev => ({
            ...prev,
            [field]: value
        }));
    };

    const updatePreference = (key, value) => {
        setUser(prev => ({
            ...prev,
            preferences: {
                ...prev.preferences,
                [key]: value
            }
        }));
    };

    return (
        <div>
            <input 
                value={user.name}
                onChange={(e) => updateUser('name', e.target.value)}
                placeholder="Name"
            />
            <input 
                value={user.email}
                onChange={(e) => updateUser('email', e.target.value)}
                placeholder="Email"
            />
            <select 
                value={user.preferences.theme}
                onChange={(e) => updatePreference('theme', e.target.value)}
            >
                <option value="light">Light</option>
                <option value="dark">Dark</option>
            </select>
        </div>
    );
}

// State with arrays
function TodoList() {
    const [todos, setTodos] = useState([]);
    const [newTodo, setNewTodo] = useState('');

    const addTodo = () => {
        if (newTodo.trim()) {
            setTodos(prev => [...prev, {
                id: Date.now(),
                text: newTodo,
                completed: false
            }]);
            setNewTodo('');
        }
    };

    const toggleTodo = (id) => {
        setTodos(prev => prev.map(todo =>
            todo.id === id 
                ? { ...todo, completed: !todo.completed }
                : todo
        ));
    };

    const deleteTodo = (id) => {
        setTodos(prev => prev.filter(todo => todo.id !== id));
    };

    return (
        <div>
            <input 
                value={newTodo}
                onChange={(e) => setNewTodo(e.target.value)}
                placeholder="Add new todo"
            />
            <button onClick={addTodo}>Add</button>
            <ul>
                {todos.map(todo => (
                    <li key={todo.id}>
                        <input 
                            type="checkbox"
                            checked={todo.completed}
                            onChange={() => toggleTodo(todo.id)}
                        />
                        <span style={{
                            textDecoration: todo.completed ? 'line-through' : 'none'
                        }}>
                            {todo.text}
                        </span>
                        <button onClick={() => deleteTodo(todo.id)}>Delete</button>
                    </li>
                ))}
            </ul>
        </div>
    );
}

Practice Exercise: State Management

Example
// Exercise: Build a Shopping Cart
// Create a shopping cart with state management

// src/components/ShoppingCart.js
import React, { useState } from 'react';

function ShoppingCart() {
    const [cart, setCart] = useState([]);
    const [products] = useState([
        { id: 1, name: 'Laptop', price: 999, stock: 5 },
        { id: 2, name: 'Mouse', price: 25, stock: 10 },
        { id: 3, name: 'Keyboard', price: 75, stock: 8 }
    ]);

    const addToCart = (product) => {
        setCart(prev => {
            const existingItem = prev.find(item => item.id === product.id);
            if (existingItem) {
                return prev.map(item =>
                    item.id === product.id
                        ? { ...item, quantity: item.quantity + 1 }
                        : item
                );
            } else {
                return [...prev, { ...product, quantity: 1 }];
            }
        });
    };

    const removeFromCart = (productId) => {
        setCart(prev => prev.filter(item => item.id !== productId));
    };

    const updateQuantity = (productId, newQuantity) => {
        if (newQuantity <= 0) {
            removeFromCart(productId);
        } else {
            setCart(prev => prev.map(item =>
                item.id === productId
                    ? { ...item, quantity: newQuantity }
                    : item
            ));
        }
    };

    const getTotalPrice = () => {
        return cart.reduce((total, item) => total + (item.price * item.quantity), 0);
    };

    return (
        <div className="shopping-cart">
            <div className="products">
                <h2>Products</h2>
                {products.map(product => (
                    <div key={product.id} className="product">
                        <h3>{product.name}</h3>
                        <p>{product.price}</p>
                        <p>Stock: {product.stock}</p>
                        <button onClick={() => addToCart(product)}>
                            Add to Cart
                        </button>
                    </div>
                ))}
            </div>
            
            <div className="cart">
                <h2>Shopping Cart</h2>
                {cart.length === 0 ? (
                    <p>Your cart is empty</p>
                ) : (
                    <>
                        {cart.map(item => (
                            <div key={item.id} className="cart-item">
                                <span>{item.name}</span>
                                <span>{item.price}</span>
                                <input 
                                    type="number"
                                    value={item.quantity}
                                    onChange={(e) => updateQuantity(item.id, parseInt(e.target.value))}
                                    min="1"
                                />
                                <button onClick={() => removeFromCart(item.id)}>
                                    Remove
                                </button>
                            </div>
                        ))}
                        <div className="cart-total">
                            <strong>Total: {getTotalPrice()}</strong>
                        </div>
                        <button className="checkout-btn">Checkout</button>
                    </>
                )}
            </div>
        </div>
    );
}

// Challenge: Add stock validation
// Challenge: Add a wishlist feature
// Challenge: Add discount codes

Try It Yourself — Props & State Demo

Try It Yourself — Props & State DemoHTML
HTML Editor
✓ ValidTab = 2 spaces
HTML|77 lines|3766 chars|✓ Valid syntax
UTF-8

Quick Quiz — Props & State

Additional Resources

Recommended Reading

  • React Official Documentation
  • Learning React by Alex Banks and Eve Porcello
  • React Design Patterns and Best Practices by Michele Bertoli

Online Resources

  • React Tutorial on reactjs.org
  • React DevTools Documentation
  • Create React App Documentation
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep