Introduction to State: React's Memory

Give your components a memory and unlock the power to build dynamic, interactive applications from scratch.

Lesson ProgressStep 1 of 9
🤔
0 EXP

Welcome! So far, our components are static. Let's give them a memory to make them interactive.

/* Giving our components a brain... */

What is State? A Component's Memory

Think of a React component as a small, independent machine. Props are like the fixed instructions you give it from the outside (e.g., `<Button color="blue" />`). The component can read its props, but it can't change them.

State, on the other hand, is the component's internal memory. It's any piece of data that can change *over time* based on user interaction or other events.

  • A counter's current number.
  • The text a user has typed into an input field.
  • Whether a "Read More" toggle is open or closed.
  • A list of to-do items.

When a component's state changes, React automatically re-renders the component to reflect the new data. This is the core of React's declarative nature: you tell React what the UI should look like *for a given state*, and React handles the messy work of updating the DOM.

System Check

What is the primary difference between props and state?

Advanced Holo-Simulations

0 EXP

Log in to unlock these advanced training modules and test your skills.


Achievements

🏆
State Master

Correctly use useState to create an interactive component.

🏗️
Updater Whiz

Use a setter function and a functional update.

✍️
Hook Syntax Expert

Prove your mastery of useState syntax.

Mission: Build an Interactive Counter

Create a component with a state variable `count` initialized to 0. Display the count and a button that increments the count when clicked. A.D.A. will provide real-time feedback.

A.D.A. Feedback:

> System integrity looks stable. Code is valid.

Challenge: Order the State Lifecycle

Drag the steps into the correct logical order from top to bottom.

const [val, setVal] = useState(initial);
React re-renders the component.
import { useState } from 'react';
setVal(newValue);

Challenge: Complete the Syntax

Fill in the missing parts to create a functional counter.

import {} from 'react';
const [count,] = useState(0);
<button onClick={() =>(+ 1)}>Click</button>

Consult A.D.A.

Community Holo-Net

Peer Project Review

Submit your "Interactive Counter" project for feedback from other Net-Runners.

State in Action: From Theory to Interactive UI

The `useState` hook is the heartbeat of any interactive React application. It's the mechanism that allows a component to remember information and react to changes. But understanding its nuances is key to building robust applications. Let's explore how state interacts with other essential React concepts.

1. State and User Input: Controlled Components

A primary use case for state is managing form inputs. A "controlled component" is an input element (like `<input>` or `<textarea>`) whose value is controlled by React state.

  • The `value` attribute of the input is set directly from a state variable (e.g., `value={name}`).
  • An `onChange` handler updates the state variable on every keystroke (e.g., `onChange={(e) => setName(e.target.value)}`).

This pattern makes the React component the "single source of truth" for the input's value, allowing you to easily validate input, disable buttons, or format data in real-time.

function NameForm() {
  const [name, setName] = useState('');

  return (
    <form>
      <label>Name:</label>
      <input 
        type="text" 
        value={name} 
        onChange={(e) => setName(e.target.value)} 
      />
      <p>Your name is: {name}</p>
    </form>
  );
}

2. State Updates are Asynchronous and Batched

This is a common pitfall for new developers. When you call a state setter function (like `setCount(count + 1)`), it does **not** immediately change the `count` variable.

  • Asynchronous: React schedules the state update to happen "later". If you `console.log(count)` right after `setCount()`, you'll see the *old* value.
  • Batching: If you call `setCount()` multiple times in the same function, React will "batch" them together into a single re-render for performance.

❌ Incorrect (Stale State)

function handleClick() {
  setCount(count + 1); // count is 0
  setCount(count + 1); // count is still 0
  setCount(count + 1); // count is still 0
}
// This will only increment the count to 1!

✔️ Correct (Functional Update)

function handleClick() {
  setCount(c => c + 1);
  setCount(c => c + 1);
  setCount(c => c + 1);
}
// This will correctly increment the count to 3!

When your new state depends on the previous state, always use a functional update. By passing a function, you ensure React provides the latest, "queued" state value (which we call `c` in the example).

3. The Principle of Immutability

State can hold any JavaScript value, including objects and arrays. A critical rule in React is: **never mutate state directly.** Do not modify an object or array in state. Always create a *new* object or array with the updated data.

React uses a shallow comparison to check if state has changed. If you mutate the original object, its reference in memory stays the same, and React won't "see" the change, failing to trigger a re-render.

// --- Updating an Object in State ---

// ❌ BAD: Mutating state directly
const [user, setUser] = useState({ name: 'Alice', age: 25 });
function handleAgeUp() {
  user.age = user.age + 1; // MUTATION!
  setUser(user); // React won't see this as a change
}

// ✅ GOOD: Creating a new object
function handleAgeUp() {
  setUser({
    ...user, // Copy all old properties
    age: user.age + 1 // Overwrite the one that changed
  });
}

// --- Updating an Array in State ---

// ❌ BAD: Mutating state directly
const [items, setItems] = useState(['a', 'b']);
function addItem() {
  items.push('c'); // MUTATION!
  setItems(items); // React won't re-render
}

// ✅ GOOD: Creating a new array
function addItem() {
  setItems([
    ...items, // Copy all old items
    'c'       // Add the new item
  ]);
}

// ✅ GOOD: Removing an item immutably
function removeItem(itemToRemove) {
  setItems(items.filter(item => item !== itemToRemove));
}
Key Takeaway: Think of `useState` as giving your component a superpower: the ability to remember things and react when those memories change. Always use the setter function, use functional updates when state depends on itself, and never mutate objects or arrays.

React State & Hooks Glossary

State
A JavaScript object that holds data that may change over the lifetime of a React component. It represents the component's "memory" and determines its rendered output.
Props (Properties)
Data passed down from a parent component to a child component. Props are read-only and cannot be changed by the child component.
Hook
Special functions, like `useState` or `useEffect`, that let you "hook into" React features (like state and lifecycle) from functional components. They always start with the word "use".
`useState`
The React Hook that lets you add state to functional components. It takes an initial state value as an argument and returns an array containing the current state value and a function to update it.
Re-render
The process of React calling a component's function again to update the UI. This happens automatically when a component's state or props change.
Batching
React's process of grouping multiple state updates in the same event handler into a single re-render to improve performance.
Functional Update
Passing a function to a state setter (e.g., `setCount(c => c + 1)`) instead of a new value. This is used when the new state depends on the previous state, especially during batched updates.
Immutability
The principle of not changing data or objects directly. When updating state (especially objects or arrays), you must create a new copy with the changes rather than modifying the original.
Rules of Hooks
The two rules for using Hooks: 1. Only call Hooks at the top level of your component (not in loops, conditions, or nested functions). 2. Only call Hooks from React functional components or custom Hooks.
Lazy Initial State
Passing a function to `useState` (e.g., `useState(() => computeInitialValue())`). React will only run this function on the initial render, which is useful if calculating the initial state is computationally expensive.

About the Author

Author's Avatar

TodoTutorial Team

Passionate developers and educators making programming accessible to everyone.

This article was written and reviewed by our team of web development experts, who have years of experience teaching React and building robust, scalable web applications.

Verification and Updates

Last reviewed: November 2025.

We strive to keep our content accurate and up-to-date. This tutorial is based on React 18+ and is periodically reviewed to reflect industry best practices and API changes.

External Resources

Found an error or have a suggestion? Contact us!