Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
🟢 Basics – React + Next.js Foundation  ·  Lesson 06

useState & Events

What is state?

State is data that a component remembers and that can change while the user is on the page — a counter, the text in a search box, whether a menu is open. When state changes, React re-renders the component so the screen shows the new value.

Props

  • Come from the parent
  • Read-only inside the child
  • Like function arguments

State

  • Owned by the component
  • Changed with a setter function
  • Like the component’s own memory
Props vs state

Why 'use client'?

In the Next.js App Router every component is a Server Component by default — it runs on the server and sends HTML. Server Components cannot use useState or onClick, because those need the browser. Add 'use client' at the very top of a file to make it a Client Component.

💡 Keep 'use client' files small (a button, a form, a menu) and let pages stay Server Components. That keeps your site fast.

Example 1: Counter

JSX – components/Counter.jsx
'use client' // this file runs in the browser too

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0) // [current value, function to change it]

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  )
}
JSX – app/page.jsx
// app/page.jsx — a Server Component can render a Client Component
import Counter from '@/components/Counter'

export default function Page() {
  return (
    <main>
      <h1>State demo</h1>
      <Counter />
    </main>
  )
}
🔒 localhost:3000State demoYou clicked 3 times+1

How a re-render works

Click +1onClick runssetCount(1)new stateRe-renderCounter() runs againScreen updatesshows 1next click repeats the cycle
Every setter call schedules a re-render

useState(0) returns an array of two things: the current value and a setter function. Calling the setter does not change the variable immediately; it asks React to run the component again with the new value.

Example 2: Controlled input

A controlled input keeps its text in state. React is the single source of truth, so you can validate or show live counts easily.

JSX – components/NameBox.jsx
'use client'
import { useState } from 'react'

export default function NameBox() {
  const [name, setName] = useState('')

  return (
    <div>
      <input
        value={name}                              // value comes FROM state
        onChange={(e) => setName(e.target.value)} // typing updates state
        placeholder="Type your name"
      />
      <p>{name ? `Hello, ${name}!` : 'Start typing…'}</p>
      <p>{name.length} / 20 characters</p>
    </div>
  )
}

Example 3: Show / hide a mobile menu

JSX – components/MobileMenu.jsx
'use client'
import { useState } from 'react'

export default function MobileMenu() {
  const [open, setOpen] = useState(false)
  return (
    <nav>
      <button aria-expanded={open} onClick={() => setOpen(!open)}>
        {open ? '✕ Close' : '☰ Menu'}
      </button>
      {open && (
        <ul>
          <li>Home</li><li>Courses</li><li>Contact</li>
        </ul>
      )}
    </nav>
  )
}

This is exactly how the EduSite header opens its menu on phones:

Mobile menu opened with useState
EduSite mobile menu controlled by useState(open)

Updating objects and arrays

Never change state directly. Always create a new object or array with the spread operator ..., filter or map:

JSX
const [student, setStudent] = useState({ name: 'Riya', cls: 10 })
// ✅ copy the old object, change one field
setStudent({ ...student, cls: 11 })

const [todos, setTodos] = useState(['Revise loops'])
// ✅ add item (new array)
setTodos([...todos, 'Practise arrays'])
// ✅ remove item
setTodos(todos.filter((t) => t !== 'Revise loops'))

// ❌ wrong — mutating does NOT re-render
student.cls = 11
todos.push('x')

Example 4: Mini enquiry form

JSX – components/EnquiryForm.jsx
'use client'
import { useState } from 'react'

export default function EnquiryForm() {
  const [form, setForm] = useState({ name: '', course: 'python' })
  const [sent, setSent] = useState(false)

  function handleChange(e) {
    setForm({ ...form, [e.target.name]: e.target.value }) // one handler for all fields
  }

  function handleSubmit(e) {
    e.preventDefault() // stop the full page reload
    if (form.name.trim().length < 2) return alert('Please enter your name')
    setSent(true)
  }

  if (sent) return <p>✅ Thanks {form.name}, we will call you about {form.course}.</p>

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" value={form.name} onChange={handleChange} placeholder="Name" />
      <select name="course" value={form.course} onChange={handleChange}>
        <option value="python">Python</option>
        <option value="nextjs">Next.js</option>
      </select>
      <button type="submit">Send</button>
    </form>
  )
}

Later you will replace this browser-only form with a Server Action that saves the enquiry on the server.

Common mistakes

  • Forgetting 'use client' → build error about hooks in Server Components.
  • onClick={setCount(count + 1)} (no arrow) → runs during render and causes an infinite loop. Write onClick={() => setCount(count + 1)}.
  • Mutating arrays with push → screen does not update.
  • Calling useState inside an if or loop → hooks must be called at the top level of the component.

Summary

  • const [value, setValue] = useState(initial) stores changing data.
  • Calling the setter re-renders the component.
  • Events: onClick, onChange, onSubmit take functions.
  • State and events need 'use client' in Next.js.
✅ Practice

Build a "Like" button that shows ♡ 0 and turns into ❤️ with the count increasing on each click, plus an "Undo" button.

Frequently Asked Questions

Why does my variable change but the screen does not?
A normal variable does not tell React to re-render. Store the value with useState and change it with the setter function; React then updates the screen.
Why do I get "useState only works in Client Components"?
In the App Router, components are Server Components by default. Add 'use client' as the first line of the file to make it a Client Component that can use state and events.
When should I use setCount(c => c + 1) instead of setCount(count + 1)?
Use the function form when the new value depends on the old value, especially if you update several times in a row. It always receives the latest value.
Is state kept after page refresh?
No. State lives in memory and resets on refresh. To keep data, save it in a database, a cookie or localStorage.
← Next.js Tutorial
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicuseEffect & Side Effects Your progress: 6 / 37 (16%) · Lesson 7 / 37 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free