Lesson 1.6

Understanding State

When you first encounter React, the workflow seems almost too straightforward. You write JSX to describe your UI, wrap that JSX inside a function, and you get a component. Simple.

What you'll learn
  • Why plain JavaScript variables don't work as state
  • How useState solves the problem of preserving values between renders
  • How useState works and what it returns
  • When React re-renders components
  • The fundamentals of working with state in React

But there is a third ingredient that transforms a static React component into something interactive and dynamic: state.

State — specifically a component's ability to own and manage its own data over time — is what makes React a powerful tool for building modern interfaces. Without it, React would be nothing more than a templating engine.

Let's explore why state exists, why regular JavaScript variables aren't enough, and how useState solves the problem.

Why Plain JavaScript Variables Don't Work as State

Imagine you're building a small counter component that displays how many times a user has pressed a button. If you're thinking in JavaScript alone, the first attempt might look like this:

jsx
export default function Counter() {
  let clicks = 0

  function increment() {
    clicks += 1
  }

  return (
    <button onClick={increment}>
      {clicks}
    </button>
  )
}

At first glance, this appears reasonable. Components are functions. Functions can have variables. Variables can change. So this should work… right?

Unfortunately, this fails completely. The reason is simple:

Every time React calls your component function, all variables inside it reset

This is not a React quirk. It's pure JavaScript behavior.

To see the underlying mechanics more clearly, remove React from the equation:

javascript
function runCounter() {
  let value = 0
  value += 1
  return value
}

console.log(runCounter()) // 1
console.log(runCounter()) // 1
console.log(runCounter()) // 1

Each function call starts from a fresh scope, creating its own value. No information carries over between calls.

React behaves the same way. Every render is just another function call. So unless React provides a way to preserve data between calls, you cannot store state inside a function.

Enter useState: React's State Management Hook

React solves this problem with hooks. Hooks are special functions that allow you to declare that your component needs a certain React capability — like state, context, lifecycle access, or refs.

The first hook you encounter is typically useState.

javascript
const result = React.useState("initial value")
const currentValue = result[0]
const updateValue = result[1]

useState does two things:

  • It tells React to remember a value between renders
  • It provides a function that updates that value and triggers a re-render

However, accessing the returned array through indexing is clunky. Instead, we use array destructuring.

Cleaner Code with Array Destructuring

JavaScript allows us to pull items out of an array directly:

javascript
const numbers = [3, 6, 9]
const [a, b, c] = numbers

We can apply the same pattern to useState:

javascript
const [value, setValue] = React.useState("Initial value")

Much easier to read, and it expresses intent clearly.

Rewriting the Counter using useState

Let's revisit our broken counter and rebuild it using useState. Here is a fresh example, different from the original one:

jsx
export default function ClickTracker() {
  const [totalClicks, setTotalClicks] = React.useState(0)

  function handlePress() {
    setTotalClicks(prev => prev + 1)
  }

  return (
    <button onClick={handlePress}>
      Clicked {totalClicks} times
    </button>
  )
}

Now this works exactly as expected.

Why?

Because React:

  • Stores totalClicks somewhere internally
  • Calls your component again whenever you call setTotalClicks
  • Supplies the stored value back into the component on each render
  • Rebuilds the UI based on the latest state

Your component becomes a pure function of current state and props.

When Does React Re-render?

This topic has its own chapter in most React courses, but here is the distilled rule:

React re-renders a component whenever its state (or props) change.

A mental model:

STATE change → React calls component again → React updates the DOM

In the ClickTracker example, each button press:

  • Calls setTotalClicks
  • Updates the internal state
  • Triggers a re-render
  • Outputs a new UI that reflects the updated number

This loop — state change, re-render, UI update — is the foundation of interactive React applications.

Summary

State is the key ingredient that unlocks React's ability to build dynamic UIs.

Understanding why plain JavaScript variables reset, how useState preserves values across renders, and why React re-renders is essential to mastering the framework.

As you progress, you'll encounter more hooks — useEffect, useRef, useMemo, and others—but useState remains the most fundamental tool: simple, powerful, and always relevant.