React State Explained (useState Hook)
React applications become interactive because they can respond to user actions such as clicking a button, submitting a form, adding products to a cart, or updating profile information. But how does React remember those values?
The answer is State.
State is one of the most important concepts in React because it allows components to store information that changes over time. Whenever state changes, React automatically updates the user interface to display the latest data.
If you've already learned about JSX, Components and Props, then State is the next major concept you should master before moving on to Hooks like useEffect or React Router.
In this guide, we'll learn everything about React State from beginner to intermediate level with practical examples and best practices.
What You'll Learn
By the end of this guide you'll understand:
- What State is
- Why React needs State
- Why normal JavaScript variables don't work
- The useState Hook
- Updating State
- Multiple State Variables
- Object State
- Array State
- Functional Updates
- Best Practices
- Common Mistakes
- Real-world Examples
- React Interview Questions
Prerequisites
Before reading this article, you should understand:
- JavaScript Variables
- JavaScript Functions
- ES6 Arrow Functions
- React Components
- React Props
- JSX
If you haven't covered these topics yet, we recommend reading our previous React articles first.
What is State?
State is data that belongs to a React component and can change while the application is running.
Whenever State changes, React automatically updates the component and refreshes the UI.
Think of State as the memory of a component.
For example:
- Counter value
- Logged-in user
- Shopping cart
- Theme (Dark / Light)
- Search input
- Product quantity
- Notification count
All these values change while users interact with your application.
State makes those changes possible.
Real-Life Analogy
Imagine a whiteboard in your office.
You write today's meeting schedule on it.
Whenever someone changes the meeting time, you erase the old information and write the new one.
The whiteboard always displays the latest information.
React State works exactly the same way.
Instead of manually erasing and rewriting, React automatically updates the screen whenever the State changes.
Why Do We Need State?
Let's build a simple counter.
jsxfunction Counter() { let count = 0; function increment() { count++; console.log(count); } return ( <> <h1>{count}</h1> <button onClick={increment}> Increment </button> </> ); }
When you click the button, the console prints:
1
2
3
4
But the UI still displays:
0
Why?
Because changing a normal JavaScript variable does not tell React to re-render the component.
React has no idea that count has changed.
Why Normal Variables Don't Work
A React component runs like a JavaScript function.
Whenever React renders a component, the function executes from the beginning.
That means:
jsxlet count = 0;
is created again every render.
React doesn't remember previous values stored in normal variables.
Instead, React only remembers values stored in State.
Introducing useState
React provides a Hook called useState.
It allows components to store values between renders.
First import it.
jsximport { useState } from "react";
Now create State.
jsxconst [count, setCount] = useState(0);
Let's understand every part.
| Code | Meaning |
|---|---|
| useState | React Hook |
| 0 | Initial value |
| count | Current State |
| setCount | Function used to update State |
React returns an array containing two values.
We use Array Destructuring to access them.
Building Our First Counter
Now replace the previous example with this.
jsximport { useState } from "react"; function Counter() { const [count, setCount] = useState(0); function increment() { setCount(count + 1); } return ( <> <h1>{count}</h1> <button onClick={increment}> Increment </button> </> ); } export default Counter;
Now every click updates both:
- State
- User Interface
The counter becomes interactive.
How React Updates the UI
When you click the button, React performs these steps.
User Clicks Button
↓
increment()
↓
setCount()
↓
State Changes
↓
React Re-renders Component
↓
Updated UI Appears
This automatic rendering is one of the biggest advantages of React.
Developers only update the State.
React takes care of updating the DOM efficiently.
Breaking Down useState
Let's examine this line again.
jsxconst [count, setCount] = useState(0);
count
Stores the current value.
Initially:
0
After clicking:
1
2
3
setCount
This function updates the State.
Never write:
jsxcount = 5;
Instead write:
jsxsetCount(5);
Only React should update State.
Initial Value
Whatever you pass inside useState becomes the initial value.
Examples:
jsxuseState(0)
Number
jsxuseState("")
String
jsxuseState(false)
Boolean
jsxuseState([])
Array
jsxuseState({})
Object
React supports storing almost any JavaScript data type inside State.
State vs Props
Many beginners confuse Props and State.
Here's the difference.
| Props | State |
|---|---|
| Passed from Parent | Managed by Component |
| Read Only | Can Change |
| External Data | Internal Data |
| Cannot Modify | Updated using setState |
A simple rule:
Props come from outside.
State lives inside the component.
Quick Summary
So far you've learned:
- What State is
- Why State exists
- Why normal variables don't work
- How useState works
- How React updates the UI
- Difference between Props and State
In the next section, we'll learn how to work with multiple state variables, objects, arrays, and functional updates, along with practical real-world examples.
Working with Multiple State Variables
A component can manage more than one piece of State.
For example, a login form needs to store:
- Password
- Loading Status
- Error Message
Instead of combining everything into one variable, React allows us to create multiple State variables.
jsximport { useState } from "react"; function LoginForm() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [loading, setLoading] = useState(false); return ( <> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> <button> Login </button> </> ); }
Every state variable has its own responsibility.
This makes the component easier to understand and maintain.
Why Use Multiple State Variables?
Imagine storing everything inside one variable.
jsxconst [data, setData] = useState({ email: "", password: "", loading: false, error: "" });
This works.
However, if those values are unrelated, managing them separately usually makes the code cleaner.
Good examples of separate State:
- Search Text
- Selected Category
- Modal Visibility
- Loading Spinner
Each value changes independently.
State Can Store Different Data Types
State is not limited to numbers.
React can store almost every JavaScript data type.
Number
jsxconst [count, setCount] = useState(0);
String
jsxconst [name, setName] = useState("");
Boolean
jsxconst [isLoggedIn, setIsLoggedIn] = useState(false);
Array
jsxconst [products, setProducts] = useState([]);
Object
jsxconst [user, setUser] = useState({});
Null
jsxconst [customer, setCustomer] = useState(null);
Choose the data type that best represents your information.
State with Objects
Objects are useful when several values belong together.
Example:
jsxconst [user, setUser] = useState({ name: "John", email: "john@example.com", age: 30 });
Displaying values:
jsx<h2>{user.name}</h2> <p>{user.email}</p> <p>{user.age}</p>
Updating Object State
Many beginners make this mistake.
❌ Wrong
jsxuser.age = 31; setUser(user);
Never modify State directly.
React may not detect the change correctly.
Always create a new object.
✅ Correct
jsxsetUser({ ...user, age: 31 });
Why Do We Use the Spread Operator?
Suppose our object contains:
jsx{ name: "John", email: "john@example.com", age: 30 }
If we write:
jsxsetUser({ age: 31 });
The new object becomes:
jsx{ age: 31 }
Everything else disappears.
The spread operator copies the existing properties.
jsxsetUser({ ...user, age: 31 });
Result:
jsx{ name: "John", email: "john@example.com", age: 31 }
Only the required property changes.
State with Arrays
Arrays are extremely common.
Examples:
-
Shopping Cart
-
Product List
-
Notifications
-
Messages
-
Todo List
Create an empty array.
jsxconst [todos, setTodos] = useState([]);
Adding Items
jsxsetTodos([ ...todos, "Learn React" ]);
If todos initially contains:
jsx["Learn JSX"]
After adding:
jsx["Learn JSX","Learn React"]
React re-renders the component automatically.
Rendering Arrays
jsx<ul> {todos.map((todo,index)=>( <li key={index}> {todo} </li> ))} </ul>
Whenever State changes, the list updates instantly.
Removing Items
Example:
jsxconst removeTodo = (index) => { setTodos( todos.filter((_, i) => i !== index) ); };
React creates a new array without modifying the original one.
Updating Array Items
jsxsetTodos( todos.map((todo,index)=> index===1 ? "Complete React Course" : todo ) );
Again, we return a completely new array.
Functional State Updates
Earlier we wrote:
jsxsetCount(count + 1);
This usually works.
However, sometimes multiple updates happen very quickly.
React recommends using a functional update.
jsxsetCount(previousCount => previousCount + 1);
Here:
jsxpreviousCount
always contains the latest State value.
This prevents bugs caused by stale values.
Why Functional Updates Matter
Suppose we write:
jsxsetCount(count + 1); setCount(count + 1); setCount(count + 1);
You might expect:
3
But React batches updates.
Instead, you may only get:
1
Correct approach:
jsxsetCount(previous => previous + 1); setCount(previous => previous + 1); setCount(previous => previous + 1);
Now the result becomes:
3
This is the preferred approach whenever the next value depends on the previous value.
Real-world Example
Imagine an eCommerce website.
When customers click:
Add To Cart
The application needs to update State.
jsxconst [cartItems, setCartItems] = useState([]);
Adding products:
jsxsetCartItems([ ...cartItems, product ]);
Immediately the UI updates.
-
Cart Count
-
Mini Cart
-
Checkout Summary
Everything refreshes automatically because React State changed.
Another Example: Theme Switcher
jsxconst [darkMode, setDarkMode] = useState(false);
Toggle:
jsx<button onClick={()=> setDarkMode(!darkMode) } > Toggle Theme </button>
Changing one Boolean value updates the entire application's appearance.
Key Takeaways
At this point you've learned:
- Multiple State Variables
- Object State
- Array State
- Updating Objects
- Updating Arrays
- Functional Updates
- Real-world Examples
In the next section we'll cover:
- Best Practices
- Common Mistakes
- Performance Tips
- Interview Questions
- Frequently Asked Questions
- Summary
- Next Lesson
Best Practices for Managing State
As your React applications grow, managing State properly becomes increasingly important. Poor State management can make components difficult to understand, harder to maintain, and less efficient.
Here are some best practices followed by experienced React developers.
1. Keep State as Small as Possible
Only store information that can change.
For example:
jsxconst [searchText, setSearchText] = useState("");
Avoid storing values that can be calculated from other data.
❌ Bad
jsxconst [totalPrice, setTotalPrice] = useState(0);
If totalPrice is simply the sum of the cart items, calculate it when rendering instead of storing it separately.
jsxconst totalPrice = cartItems.reduce( (total, item) => total + item.price, 0 );
This keeps your State simple and avoids synchronization problems.
2. Never Mutate State Directly
Always create a new object or array.
❌ Wrong
jsxuser.name = "Peter"; setUser(user);
✅ Correct
jsxsetUser({ ...user, name: "Peter" });
Mutating State directly can lead to bugs because React may not detect the change.
3. Split Unrelated State
Instead of:
jsxconst [data, setData] = useState({ search: "", darkMode: false, loading: false });
Prefer:
jsxconst [search, setSearch] = useState(""); const [darkMode, setDarkMode] = useState(false); const [loading, setLoading] = useState(false);
Each State variable now has a single responsibility.
4. Use Functional Updates When Needed
Whenever the next value depends on the previous value, use a callback.
jsxsetCount(previous => previous + 1);
This avoids problems caused by React batching updates.
5. Use Meaningful Names
Good
jsxconst [cartItems, setCartItems] = useState([]);
Bad
jsxconst [data, setData] = useState([]);
Descriptive names make code easier to understand.
Common Mistakes Beginners Make
Learning from mistakes is just as important as learning the correct approach.
Mistake 1
Updating State directly.
❌
jsxuser.age = 35;
Always use the setter function.
Mistake 2
Expecting State to update immediately.
jsxsetCount(count + 1); console.log(count);
Many beginners expect:
1
But the console often prints:
0
This happens because React schedules the update.
The new value becomes available during the next render.
Mistake 3
Creating unnecessary State.
Suppose you have:
jsxconst [firstName, setFirstName] = useState("John"); const [lastName, setLastName] = useState("Doe");
Don't also create:
jsxconst [fullName, setFullName] = useState("");
Instead:
jsxconst fullName = `${firstName} ${lastName}`;
If something can be calculated, don't store it.
Mistake 4
Mutating Arrays
❌
jsxtodos.push("React"); setTodos(todos);
✅
jsxsetTodos([ ...todos, "React" ]);
Always create a new array.
Mistake 5
Using One Huge State Object
Large State objects become difficult to maintain.
Split unrelated information into separate State variables whenever possible.
Real-world Examples
Let's see where State is used in real applications.
Shopping Cart
State stores:
- Products
- Quantity
- Total Price
Whenever a customer adds an item, React updates the UI automatically.
Login Form
State stores:
- Password
- Loading
- Error Message
Every keystroke updates the component.
Dark Mode
jsxconst [darkMode, setDarkMode] = useState(false);
Changing one Boolean value updates the entire application's appearance.
Search Box
jsxconst [query, setQuery] = useState("");
Every key press filters products instantly.
Notifications
jsxconst [notifications, setNotifications] = useState([]);
Whenever a new notification arrives, the UI refreshes automatically.
Interview Questions
1. What is State in React?
State is data managed inside a component that can change over time. Whenever State changes, React re-renders the component.
2. What is the difference between Props and State?
Props are passed from a parent component and are read-only.
State belongs to a component and can be updated.
3. What is useState?
useState is a React Hook used to create and manage State inside functional components.
4. Why shouldn't we modify State directly?
React relies on detecting new objects and arrays to know when to re-render. Direct mutation can prevent updates and introduce bugs.
5. Can State store objects?
Yes.
jsxconst [user, setUser] = useState({});
6. Can State store arrays?
Yes.
jsxconst [products, setProducts] = useState([]);
7. When should you use functional updates?
Whenever the next State depends on the previous State.
jsxsetCount(previous => previous + 1);
8. Does updating State reload the page?
No.
Only the affected component is re-rendered.
9. Is State synchronous?
No.
React schedules State updates for better performance.
10. Can one component have multiple State variables?
Yes.
This is a common and recommended practice when the values are unrelated.
Frequently Asked Questions
Can I use useState inside loops?
No.
Hooks must always be called at the top level of a component.
Can State be null?
Yes.
jsxconst [user, setUser] = useState(null);
Should every variable be State?
No.
Only values that change and affect the UI should be stored in State.
Can I update multiple State variables together?
Yes.
React batches updates to improve performance.
Summary
Congratulations! 🎉
You now understand one of the most important concepts in React.
In this guide, you learned:
- What State is
- Why React needs State
- The useState Hook
- Multiple State variables
- Object State
- Array State
- Functional updates
- Best practices
- Common mistakes
- Real-world examples
- Interview questions
Mastering State is essential because almost every React application depends on it.
Once you're comfortable with State, learning Hooks like useEffect, useMemo, and Context API becomes much easier.
Related Articles
- What is React?
- Install React with Vite
- JSX Explained
- React Components Explained
- React Props Explained
- React Project Structure Explained
Next Lesson
➡ Handling Events in React
In the next article, you'll learn how React handles user interactions such as button clicks, form submissions, keyboard events, and mouse events using the onClick, onChange, onSubmit, and other event handlers.



