React: State Basics: useState

Last updated: 2026-10-26

State is a component’s memory. If Props are parameters given to you by others (read-only), then State is your own little notebook (editable). useState is the “memory chip” that React installs in a component.


1. What You'll Learn



2. Reflections Triggered by a Counter

(1) Pain Point: Regular variables do not trigger UI updates

Bob wants to make a simple counter: when you click the button, the number increases by 1.

▶ Try it Yourself

Bob discovered a problem: Ordinary variables do not notify React to update the UI. Every time the component re-renders, count is reset to 0.

(2) A Solution Using useState

▶ Try it Yourself

Return Value: useState returns an array [current value, setter function]. After calling setCount, React automatically re-renders the component to display the latest values.



3. Core Concepts of useState

(1) Deconstructing Assignment

JSX
import { useState } from 'react'

// useState(initialValue) Back [value, setValue]
const [count, setCount] = useState(0)
//      ^      ^          ^
//      |      |          └─ Initial value(Applies only to the first render)
//      |      └─ Update Function(Triggers a re-render after being called)
//      └─ Current status value(Get the latest value on every render)
▶ Try it Yourself
Section Description
count Current state value; the latest value is retrieved with each render
setCount Update function: Calling it → React re-renders the component
useState(0) Initial value (used during the first render; ignored in subsequent renders)

(2) Update Mechanism

▶ Try it Yourself

Key Concept: setCount(count + 1) means "ask React to update count on the next render," not "immediately change count." This is called asynchronous updating.

(3) Functional Updates

If the new state depends on the old state, you should use functional updates:

▶ Try it Yourself
Method Syntax Characteristics
Update Directly setCount(count + 1) Simple, but data is lost with consecutive calls
Functional Update setCount(prev => prev + 1) Accurate; works correctly even with consecutive calls


4. Updating Arrays and Objects (Immutability)

React requires that state not be modified directly. Never use state.push() or state.name = 'xxx'; instead, create a new array or object to replace the old value.

(1) Objects to Update

▶ Try it Yourself

(2) Update the array

▶ Try it Yourself

Output:

TEXT
State: arr

▶ Example: Array Operations Quick Reference Table

JSX
// ============================================
// Example:React Array Operations in C 6 Common Scenarios
// ============================================

const [arr, setArr] = useState([1, 2, 3])

// 1. Append to the end
setArr([...arr, 4])           // [1, 2, 3, 4]

// 2. Add to the beginning
setArr([0, ...arr])           // [0, 1, 2, 3]

// 3. Insert in the middle
const insertAt = 1
setArr([...arr.slice(0, insertAt), 99, ...arr.slice(insertAt)])
                              // [1, 99, 2, 3]

// 4. Delete Element(filter)
setArr(arr.filter(n => n !== 2))  // [1, 3]

// 5. Update Element(map)
setArr(arr.map(n => n === 2 ? 22 : n))  // [1, 22, 3]

// 6. Sort(Copy first, then sort)
setArr([...arr].sort((a, b) => b - a))  // [3, 2, 1]
▶ Try it Yourself

Output:

TEXT
Array state operations: push → add item, filter → remove item, map → update item. Each returns a new array reference for React re-rendering


5. Multiple State Variables

A component can have multiple state variables. It is recommended to break them down by logic rather than cramming them into a single large object:

JSX
function RegistrationForm() {
  // ✅ Recommendations:Logical Breakdown
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [errors, setErrors] = useState({})

  // ❌ Not recommended:All states are stored in a single object
  const [form, setForm] = useState({
    name: '', email: '', password: '',
    isSubmitting: false, errors: {}
  })
  // Expand the entire object when updating,Fields that are easy to overlook
}
▶ Try it Yourself
Strategy Advantages Disadvantages
Split into multiple useStates Precise updates, type-safe, and easy to read Too many variables when there's a lot of state
Combined into a single useState Convenient for updating multiple fields at once The update syntax is cumbersome and it's easy to forget to expand it

Recommendation: Use multiple useState instances for independent states (such as input fields, loading indicators, and error messages); logically related fields (such as all fields in a user profile) can be combined into a single object.



6. Lifting State Up

When multiple components need to share the same state, lift the state up to their nearest common parent component.

100%
graph TB
    subgraph "Before the status upgrade(Data is not shared)"
        A[Parent Component App] --- B[Child component A<br/>Have their own count]
        A --- C[Child component B<br/>Have their own count]
    end
    
    subgraph "After the status upgrade(Data Sharing)"
        D[Parent Component App<br/>**count Here**] --- E[Child component A<br/>Read count, Call setCount]
        D --- F[Child component B<br/>Read count, Call setCount]
    end

Output:

TEXT
State: arr (setter: setArr)

▶ Example: Practical Application of State Promotion

▶ Try it Yourself

Output:

TEXT
Enter 100 in Celsius → Fahrenheit auto-shows 212.0. Displays "100°C = 212.0°F". Two inputs stay synchronized.


7. Complete Example: Shopping Cart Counter

▶ Expand runnable example (96 lines)
▶ Try it Yourself

Output:

TEXT
Subheading: "Temperature Converter". Displays: "Celsius(°C):". State: temperature (setter: setTemperature)

Interaction Flow:

  • Tap +/− to adjust the quantity; the subtotal and total are updated in real time
  • Click ✕ to delete an item; display a friendly prompt when the shopping cart is empty
  • Enter the promo code REACT2026 to save 20 yuan

▶ Example 3: Updating an Object's State—Editing User Information

JSX
function UserEditor() {
  const [user, setUser] = useState({ name: 'Alice', email: 'alice@test.com', age: 28 })

  function updateField(field, value) {
    setUser(prev => ({ ...prev, [field]: value }))
  }

  return (
    <div style={{ maxWidth: 400, margin: '0 auto' }}>
      <h3>Edit Profile</h3>
      <input value={user.name} onChange={e => updateField('name', e.target.value)}
        placeholder="Name" style={{ width: '100%', padding: 8, marginBottom: 8, borderRadius: 4 }} />
      <input value={user.email} onChange={e => updateField('email', e.target.value)}
        placeholder="Email" style={{ width: '100%', padding: 8, marginBottom: 8, borderRadius: 4 }} />
      <input type="number" value={user.age} onChange={e => updateField('age', Number(e.target.value))}
        placeholder="Age" style={{ width: '100%', padding: 8, marginBottom: 8, borderRadius: 4 }} />
      <pre style={{ background: '#f5f5f5', padding: 12, borderRadius: 4, fontSize: 13 }}>
        {JSON.stringify(user, null, 2)}
      </pre>
    </div>
  )
}
▶ Try it Yourself

Output:

TEXT
State: address. Inputs: Street, City, ZIP

Output:

TEXT
Displays: "Edit Profile". State: user (setter: setUser). Input: Name, Email, Age

▶ Example 4: Nested Object States—Address Management

▶ Try it Yourself

Output:

TEXT
Shipping form: Street, City, ZIP, Country dropdown (US/CN/JP), "Primary address" checkbox. All fields update state reactively.

Output:

TEXT
Displays: "Shipping Address". State: address (setter: setAddress). Input: Street, City, ZIP. Dropdown: United States, China, Japan

▶ Example 5: Functional Updates Solve the Problem of Batch Updates

▶ Try it Yourself

Output:

TEXT
Score: 0, Multiplier: x1. +10/+50/+100 add points×multiplier. "2x Multiplier" doubles (max x8). Reset → Score: 0, x1

❓ FAQ

Q What is the performance difference between useState and regular variables?
A useState incurs additional overhead (tracking changes, scheduling rendering), so it should only be used in scenarios where "UI updates are triggered when changes occur." If a variable changes but does not require a UI update (such as a timer ID or scroll position), using useRef (Lesson 10) is more appropriate.
Q How many useStates can there be in a single component? Are there any performance issues?
A There is no limit on the number. The official React documentation recommends breaking things down into multiple useStates based on logic rather than using a single large object. Each useState call is a "state unit," and React can efficiently handle a large number of useStates. Common components typically have 3–8 useStates.
Q Is a setState update synchronous or asynchronous?
A Prior to React 18, setState was "automatically batched" within event handlers, but synchronous within setTimeout and Promise calls. React 18 introduced Automatic Batching, so setState is now batch-asynchronous regardless of whether it’s called within an event handler, setTimeout, Promise, or fetch callback. If you absolutely need to access the updated DOM synchronously, you can use flushSync(() => setState(...)).

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty ⭐): Create a LikeButton component that toggles between ❤️ and 🤍 states when clicked and displays the number of likes.
  2. Advanced Exercise (Difficulty ⭐⭐): Create a ExpenseTracker component that uses useState to manage a list of expenses (description, amount, date), and supports adding and removing items.
  3. Challenge (Difficulty: ⭐⭐⭐): Create a ColorPicker component that uses three useState instances to manage the R, G, and B slider values (0–255), and displays a real-time color preview and hex color code.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏