Back to Tutorial
State and Events
Hands-on Practice
30 min

React State

Learn how to add interactivity to your React components using state with the useState hook.

Learning Objectives

  • Understand what state is and why it's important
  • Learn how to use the useState hook
  • Master state updates and immutability rules
  • Handle multiple state variables effectively
  • Build interactive components with state
  • Debug common state-related issues

React State

Welcome to one of the most important concepts in React! Up until now, our components have been pretty static - they display information but don't really change. State is what brings your components to life by making them interactive and dynamic.

Think of state like the "memory" of your component. Just like you remember your name, age, or what you had for breakfast, React components can remember information too. And when that information changes, React automatically updates what's displayed on the screen.

Why Do We Need State?

Let's start with a simple question: What if you wanted to build a counter that increases every time someone clicks a button?

With what we've learned so far, you might try something like this:

function Counter() { let count = 0; // This won't work as expected! const handleClick = () => { count = count + 1; console.log(count); // This will log the new number }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Click me!</button> </div> ); }

Try this in your head: What do you think happens when you click the button?

The answer might surprise you: The number in the console will increase, but the number on the screen will stay at 0!

Why? Because React doesn't know that something important changed. It's like having a whiteboard with a number written on it, changing the number in your head, but never erasing and rewriting the whiteboard.

Introducing React State

React state solves this problem. When you use state, you're telling React: "Hey, this piece of data is important. When it changes, please update the screen!"

Here's the same counter, but using state correctly:

import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); // This WILL update the screen! }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Click me!</button> </div> ); }

Now when you click the button, the number on screen increases! ✨

Understanding useState

Let's break down that mysterious useState line step by step:

const [count, setCount] = useState(0);

Step 1: Import useState

First, we need to import useState from React:

import React, { useState } from 'react';

Think of this like getting a special tool from React's toolbox.

Step 2: Call useState

useState(0)

We call useState and give it the starting value. In this case, we want our counter to start at 0.

Step 3: Get Two Things Back

useState gives us back two things in an array:

  1. The current value (starts at 0)
  2. A function to change that value

Step 4: Use Array Destructuring

const [count, setCount] = useState(0);

This is like saying:

  • "The first thing (current value), I'll call count"
  • "The second thing (update function), I'll call setCount"

Important: You can name these anything you want! These are all valid:

const [age, setAge] = useState(25); const [name, setName] = useState("Alice"); const [isVisible, setIsVisible] = useState(true); const [pizza, setPizza] = useState("margherita");

Your First Interactive Component

Let's build something together! We'll create a simple greeting component that lets users change their name.

Step 1: Start with the basic structure

function PersonalGreeting() { return ( <div> <h1>Hello, World!</h1> <input type="text" placeholder="Enter your name" /> </div> ); }

Step 2: Add state to remember the name

function PersonalGreeting() { const [name, setName] = useState("World"); return ( <div> <h1>Hello, {name}!</h1> <input type="text" placeholder="Enter your name" /> </div> ); }

Step 3: Connect the input to our state

function PersonalGreeting() { const [name, setName] = useState("World"); const handleNameChange = (event) => { const newName = event.target.value; setName(newName); }; return ( <div> <h1>Hello, {name}!</h1> <input type="text" placeholder="Enter your name" value={name} onChange={handleNameChange} /> </div> ); }

What's happening here?

  • When someone types in the input, handleNameChange runs
  • We get the new value from event.target.value
  • We call setName with the new value
  • React updates the screen to show the new name!

Different Types of State

State isn't just for numbers and text. You can store different types of information:

Numbers

function ScoreTracker() { const [score, setScore] = useState(0); return ( <div> <h2>Score: {score}</h2> <button onClick={() => setScore(score + 10)}> +10 points </button> </div> ); }

True/False (Booleans)

function LightSwitch() { const [isOn, setIsOn] = useState(false); return ( <div> <h2>Light is {isOn ? "ON" : "OFF"}</h2> <button onClick={() => setIsOn(!isOn)}> Toggle Light </button> </div> ); }

Lists of Things (Arrays)

function FruitList() { const [fruits, setFruits] = useState(["Apple", "Banana"]); const addOrange = () => { setFruits([...fruits, "Orange"]); }; return ( <div> <h2>My Fruits:</h2> <ul> {fruits.map((fruit, index) => ( <li key={index}>{fruit}</li> ))} </ul> <button onClick={addOrange}>Add Orange</button> </div> ); }

A Complete Example: Todo Item

Let's build something more realistic - a single todo item that can be marked as complete:

function TodoItem() { const [task, setTask] = useState("Learn React State"); const [isCompleted, setIsCompleted] = useState(false); const toggleComplete = () => { setIsCompleted(!isCompleted); }; return ( <div style={{ padding: "10px", backgroundColor: isCompleted ? "#d4edda" : "#fff3cd", border: "1px solid #ccc", borderRadius: "5px" }}> <h3 style={{ textDecoration: isCompleted ? "line-through" : "none" }}> {task} </h3> <button onClick={toggleComplete}> {isCompleted ? "Mark Incomplete" : "Mark Complete"} </button> <p> Status: {isCompleted ? "✅ Done!" : "⏳ In Progress"} </p> </div> ); }

What makes this interesting?

  • We have two pieces of state: the task text and whether it's completed
  • The background color changes based on completion status
  • The button text changes based on the current state
  • The task title gets crossed out when completed

Important Rules About State

Rule 1: Never Change State Directly

// ❌ DON'T do this: count = count + 1; // ✅ DO this instead: setCount(count + 1);

Why? React needs to know when things change so it can update the screen. If you change state directly, React doesn't know anything happened!

Rule 2: State Updates Are Asynchronous

This means the change doesn't happen immediately:

function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); console.log(count); // This might still show the old value! }; return <button onClick={handleClick}>Count: {count}</button>; }

Rule 3: Use Functional Updates for Dependent Changes

If your new state depends on the old state, use a function:

// ✅ Better way: const handleClick = () => { setCount(previousCount => previousCount + 1); };

Practice Exercise: Build a Mood Tracker

Try building this component yourself:

Requirements:

  • Start with a neutral mood
  • Have buttons to change mood to Happy, Sad, or Excited
  • Display different emojis based on mood
  • Show a message that changes with the mood

Hint: You'll need state that stores the current mood as a string.

Solution (try it yourself first!):

function MoodTracker() { const [mood, setMood] = useState("neutral"); const getMoodEmoji = () => { switch(mood) { case "happy": return "😊"; case "sad": return "😢"; case "excited": return "🤩"; default: return "😐"; } }; const getMoodMessage = () => { switch(mood) { case "happy": return "You're feeling great!"; case "sad": return "Hope your day gets better!"; case "excited": return "You're full of energy!"; default: return "You're feeling neutral."; } }; return ( <div style={{ textAlign: "center", padding: "20px" }}> <h2>How are you feeling?</h2> <div style={{ fontSize: "60px", margin: "20px" }}> {getMoodEmoji()} </div> <p style={{ fontSize: "18px", margin: "20px" }}> {getMoodMessage()} </p> <div> <button onClick={() => setMood("happy")}>Happy</button> <button onClick={() => setMood("sad")}>Sad</button> <button onClick={() => setMood("excited")}>Excited</button> <button onClick={() => setMood("neutral")}>Neutral</button> </div> </div> ); }

What We've Learned

Congratulations! You now understand:

What state is - the "memory" of your component
Why we need state - to make components interactive
How to use useState - the hook that adds state to components
Different types of state - numbers, text, booleans, arrays
State rules - never modify directly, always use the setter function

Common Beginner Mistakes

Mistake 1: Forgetting to Import useState

// ❌ This will cause an error: function Counter() { const [count, setCount] = useState(0); // useState is not defined! } // ✅ Always import it: import React, { useState } from 'react';

Mistake 2: Calling the Setter Function Instead of Passing It

// ❌ Wrong: <button onClick={setCount(count + 1)}>+</button> // ✅ Correct: <button onClick={() => setCount(count + 1)}>+</button>

Mistake 3: Trying to Use State Immediately After Setting It

// ❌ This won't work as expected: const handleClick = () => { setCount(count + 1); console.log(count); // Still shows old value }; // ✅ Use useEffect if you need to do something after state changes

What's Next?

In our next lesson, we'll learn about Event Handling - how to respond to user clicks, form inputs, and other interactions. You'll discover how to make your components respond to user actions in more sophisticated ways.

State and events work hand-in-hand to create truly interactive user interfaces!

Quick Recap Quiz

Before moving on, try to answer these questions:

  1. What hook do you use to add state to a functional component?
  2. What two things does useState return?
  3. How do you update state in React?
  4. Why can't you just change a variable directly instead of using state?

Answers: 1) useState, 2) Current value and setter function, 3) Using the setter function, 4) React won't know to re-render the component