Module 2: React Hooks

Learn React Hooks including useState, useEffect, useContext, and custom hooks. Master modern React development patterns.

Back to Course|4.5 hours|Intermediate

React Hooks

Learn React Hooks including useState, useEffect, useContext, and custom hooks. Master modern React development patterns.

Progress: 0/4 topics completed0%

Select Topics Overview

Introduction to Hooks

Understand the fundamentals of React Hooks and why they were introduced

Content by: Kriyansh Khunt

MERN Stack Developer

Connect

What are React Hooks?

React Hooks are functions that allow you to use state and other React features in function components. They were introduced in React 16.8 to allow you to use state and other React features without writing a class.

Why Hooks?

  • Use state and other React features without classes
  • Reuse stateful logic between components
  • Split one component into smaller functions
  • Avoid complex patterns like render props and HOCs

Rules of Hooks

  • Only call hooks at the top level of your function
  • Don't call hooks inside loops, conditions, or nested functions
  • Only call hooks from React function components or custom hooks
  • Hooks must be called in the same order every time

Basic Hook Example

Code Example
import React, { useState } from 'react';

function Example() {
    // Declare a new state variable called "count"
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

// Before Hooks (Class Component)
class Example extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count: 0 };
    }

    render() {
        return (
            <div>
                <p>You clicked {this.state.count} times</p>
                <button onClick={() => this.setState({ count: this.state.count + 1 })}>
                    Click me
                </button>
            </div>
        );
    }
}
Swipe to see more code

Hooks vs Class Components

Code Example
// Class Component with multiple state
class UserProfile extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: '',
            email: '',
            age: 0,
            isEditing: false
        };
    }

    handleNameChange = (e) => {
        this.setState({ name: e.target.value });
    };

    handleEmailChange = (e) => {
        this.setState({ email: e.target.value });
    };

    toggleEditing = () => {
        this.setState(prevState => ({
            isEditing: !prevState.isEditing
        }));
    };

    render() {
        return (
            <div>
                {this.state.isEditing ? (
                    <div>
                        <input 
                            value={this.state.name}
                            onChange={this.handleNameChange}
                        />
                        <input 
                            value={this.state.email}
                            onChange={this.handleEmailChange}
                        />
                        <button onClick={this.toggleEditing}>Save</button>
                    </div>
                ) : (
                    <div>
                        <h2>{this.state.name}</h2>
                        <p>{this.state.email}</p>
                        <button onClick={this.toggleEditing}>Edit</button>
                    </div>
                )}
            </div>
        );
    }
}

// Function Component with Hooks (equivalent)
function UserProfile() {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');
    const [age, setAge] = useState(0);
    const [isEditing, setIsEditing] = useState(false);

    const toggleEditing = () => {
        setIsEditing(!isEditing);
    };

    return (
        <div>
            {isEditing ? (
                <div>
                    <input 
                        value={name}
                        onChange={(e) => setName(e.target.value)}
                    />
                    <input 
                        value={email}
                        onChange={(e) => setEmail(e.target.value)}
                    />
                    <button onClick={toggleEditing}>Save</button>
                </div>
            ) : (
                <div>
                    <h2>{name}</h2>
                    <p>{email}</p>
                    <button onClick={toggleEditing}>Edit</button>
                </div>
            )}
        </div>
    );
}

// Advantages of Hooks:
// - Less code and boilerplate
// - Easier to understand and test
// - Better performance optimization
// - Reusable logic between components
Swipe to see more code

Practice Exercise: Converting Class to Hooks

Code Example
// Exercise: Convert a Class Component to Function Component with Hooks
// Convert this class component to use hooks

// Original Class Component
class TodoApp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            todos: [],
            inputValue: '',
            filter: 'all'
        };
    }

    componentDidMount() {
        // Load todos from localStorage
        const savedTodos = localStorage.getItem('todos');
        if (savedTodos) {
            this.setState({ todos: JSON.parse(savedTodos) });
        }
    }

    componentDidUpdate(prevProps, prevState) {
        // Save todos to localStorage when they change
        if (prevState.todos !== this.state.todos) {
            localStorage.setItem('todos', JSON.stringify(this.state.todos));
        }
    }

    addTodo = () => {
        if (this.state.inputValue.trim()) {
            this.setState(prevState => ({
                todos: [...prevState.todos, {
                    id: Date.now(),
                    text: prevState.inputValue,
                    completed: false
                }],
                inputValue: ''
            }));
        }
    };

    toggleTodo = (id) => {
        this.setState(prevState => ({
            todos: prevState.todos.map(todo =>
                todo.id === id 
                    ? { ...todo, completed: !todo.completed }
                    : todo
            )
        }));
    };

    deleteTodo = (id) => {
        this.setState(prevState => ({
            todos: prevState.todos.filter(todo => todo.id !== id)
        }));
    };

    setFilter = (filter) => {
        this.setState({ filter });
    };

    render() {
        const filteredTodos = this.state.todos.filter(todo => {
            if (this.state.filter === 'active') return !todo.completed;
            if (this.state.filter === 'completed') return todo.completed;
            return true;
        });

        return (
            <div>
                <input 
                    value={this.state.inputValue}
                    onChange={(e) => this.setState({ inputValue: e.target.value })}
                    placeholder="Add todo"
                />
                <button onClick={this.addTodo}>Add</button>
                
                <div>
                    <button onClick={() => this.setFilter('all')}>All</button>
                    <button onClick={() => this.setFilter('active')}>Active</button>
                    <button onClick={() => this.setFilter('completed')}>Completed</button>
                </div>
                
                <ul>
                    {filteredTodos.map(todo => (
                        <li key={todo.id}>
                            <input 
                                type="checkbox"
                                checked={todo.completed}
                                onChange={() => this.toggleTodo(todo.id)}
                            />
                            <span style={{
                                textDecoration: todo.completed ? 'line-through' : 'none'
                            }}>
                                {todo.text}
                            </span>
                            <button onClick={() => this.deleteTodo(todo.id)}>Delete</button>
                        </li>
                    ))}
                </ul>
            </div>
        );
    }
}

// Your Task: Convert the above class component to a function component using hooks
// Use useState for state management
// Use useEffect for side effects (localStorage)
// Maintain the same functionality

// Hint: You'll need:
// - useState for todos, inputValue, and filter
// - useEffect for localStorage operations
// - Event handlers as regular functions

// Challenge: Add a custom hook for localStorage management
// Challenge: Add a custom hook for todo filtering
// Challenge: Add a custom hook for todo operations
Swipe to see more code

🎯 Practice Exercise

Test your understanding of this topic:

Additional Resources

📚 Recommended Reading

  • React Hooks Documentation
  • React Hooks in Action by Mark Tielens Thomas
  • Custom Hooks Best Practices

🌐 Online Resources

  • React Hooks Tutorial
  • useEffect Complete Guide
  • Custom Hooks Examples

Ready for the Next Module?

Continue your learning journey and master the next set of concepts.

Continue to Module 3