State is one of the most important concepts in React. While props allow components to receive data, state allows components to store and update their own data over time.
If you want to make your React apps interactive — counters, forms, toggles, modals, inputs — you need to understand state clearly.
This guide explains state in the simplest possible way, using React + TypeScript + Vite.
✔️ Prerequisites (If you plan to practice along)
Before diving in, we should already have a working React + TypeScript project created with Vite. If not, please follow this post first: Creating Our First React App with TypeScript. That post walks you through the setup and ensures our project includes files like:
index.html
src/main.tsx
src/App.tsx
These files are essential for understanding how React components work.
🧠 1. What Is State in React?
State is internal data that a component controls.
It is:
- Changeable
- Stored inside the component
- Used to update the UI when it changes
A simple way to think about it:
📝 Props = Inputs from the parent
📝 State = Data managed by the component itself
Whenever state changes, React re-renders the component automatically.
🔢 2. Example 1 – Counter (Number State)
Let’s create a basic counter component.
Create a folder called components under the src folder (if it doesn’t already exist), and add a file named Counter.tsx with the following content:
// src/components/Counter.tsx
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
export { Counter };
✔ What’s happening here?
useState(0)creates a state variable calledcountwith a starting value of 0setCountis a function used to update that state- Clicking the button runs
setCount(count + 1), which triggers a re-render - React shows the updated
countautomatically
📝 Important Notes
1. useState must be imported
import { useState } from "react";
Here we are importing only the specific React feature we need — useState — which is why it is written inside curly braces.
2. What useState returns
useState always returns two items inside an array:
const [value, setValue] = useState(initialValue);
- value → the current state
- setValue → a function used to update that state
This pattern uses array destructuring, which lets us name each returned item clearly.
3. What is initialValue?
initialValue is the starting value for your state.
It is used only during the first render of the component.
Here we are setting a starting value of 0.
4. Understanding the return block
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
Let’s break this down:
- This is the UI that the component will show
- We are returning a button element
- When the button is clicked, the
onClickhandler runs() => setCount(count + 1)This increases the count by 1 - After calling
setCount, React re-renders the component - During the re-render, the new value of
countappears inside the button:Count: {count}
🔍 Why this works:
- React automatically updates the UI when state changes
{count}is dynamic JSX, meaning it reflects the current value- Every click creates a brand-new render with the updated number
This is the core idea behind React’s interactivity.
▶️ App Example (to run Counter)
Replace your App.tsx with this:
import { Counter } from "./components/Counter";
function App() {
return (
<div>
<h1>Counter Example</h1>
<Counter />
</div>
);
}
export default App;
✍️ 5. Example 2 — NameInput (Text State & Controlled Input)
Purpose: Handling user input with state
Create file:📄 src/components/NameInput.tsx
import { useState } from "react";
function NameInput() {
const [name, setName] = useState("");
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Type your name"
/>
<p>You typed: {name}</p>
</div>
);
}
export { NameInput };
✔ What this teaches:
- Updating state as the user types
- Storing text inside state
- Controlling the
<input />with state - Updating UI in real time
📘 Understanding the return block
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Type your name"
/>
<p>You typed: {name}</p>
</div>
);
✔ Breakdown:
<input value={name} />
The input field displays whatever is in state.onChange={(e) => setName(e.target.value)}
Runs every time the user types
→ gets the text
→ updates the state
→ triggers a re-render
→ the UI updates in real-time<p>You typed: {name}</p>{name}is a dynamic variable in JSX, showing the latest state.
This creates a fully interactive text input.
▶️ App Example (to run NameInput)
import { NameInput } from "./components/NameInput";
function App() {
return (
<div>
<h1>Name Input Example</h1>
<NameInput />
</div>
);
}
export default App;
This demonstrates controlled components, meaning the input’s value comes from React state.
🎭 6. Example 3 — ToggleMessage (Boolean State)
Purpose: Show/hide UI using a boolean value
Create:📄 src/components/ToggleMessage.tsx
import { useState } from "react";
function ToggleMessage() {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!show)}>
Toggle Message
</button>
{show && <p>Hello there!</p>}
</div>
);
}
export { ToggleMessage };
✔ What this teaches
- Boolean state (
true/false) - Toggling values with
!show - Conditional rendering using state
📘 Understanding the return block
return (
<div>
<button onClick={() => setShow(!show)}>
Toggle Message
</button>
{show && <p>Hello there!</p>}
</div>
);
✔ Breakdown:
1. Button toggles the boolean
setShow(!show)
True becomes false, false becomes true → UI updates.
2. {show && <p>Hello there!</p>} is conditional JSX
Meaning:
- If
showis true → render the<p> - If
showis false → render nothing
It’s a clean and common React pattern for showing or hiding elements.
▶️ App Example (to run ToggleMessage)
import { ToggleMessage } from "./components/ToggleMessage";
function App() {
return (
<div>
<h1>Toggle Message Example</h1>
<ToggleMessage />
</div>
);
}
export default App;
🧠 7. Important State Concepts (Must-Know Basics)
Not all state concepts require full component examples.
The following ideas are essential to understanding how state behaves in real React applications.
🔹 7.1 Multiple State Variables
A component can have as many state variables as you need.
const [count, setCount] = useState(0);
const [isVisible, setIsVisible] = useState(true);
const [color, setColor] = useState("blue");
Each state variable is:
- Independent
- Managed separately
- Updated separately
This helps keep state small and focused.
🔹 7.2 Component Instances Have Independent State
Every time you use a component, React creates a new instance — each with its own state.
<Counter /> // has its own count
<Counter /> // has a completely separate count
They do not share state.
This is why React components are:
- Predictable
- Reusable
- Isolated
It ensures one component cannot accidentally affect another.
🔹 7.3 Derived State (Computed Values)
Sometimes your UI depends on state but should not store extra state variables.
Correct:
const doubled = count * 2;
This is a derived value, calculated from existing state.
Incorrect:
const [doubled, setDoubled] = useState(count * 2);
Why not store it?
- It can go out of sync
- It creates unnecessary complexity
- It duplicates data
Rule of thumb:
If you can compute it from existing state or props, don’t store it in state.
🔌 8. Props vs State (Beginner Cheat Sheet)
| Topic | Props | State |
|---|---|---|
| Source | Parent | Component itself |
| Can change? | ❌ No | ✔ Yes |
| Who controls it? | Parent | Component |
| Re-render on change? | Yes | Yes |
| Purpose | Pass data in | Store internal data |
🎉 Final Summary
React state is what makes your UI interactive.
- State stores dynamic, changeable data
- Updating state re-renders the component
useStategives you[value, setValue]- Text inputs become controlled using state
- Boolean state controls visibility
- Props + state work together for dynamic UI
- Each component instance has isolated state
- Derived values should be computed, not stored
Mastering these examples prepares you for:
- Lifting state up
useReducer()- React Context
- Zustand or Redux
- Real-world component architecture