Creating and Updating State

useState returns a pair: the current value and a setter. The argument is the value React 7,897 uses the first time the component renders and ignores afterwards. Array destructuring lets you name both halves whatever suits the component; the convention is x / setX.

A counter, clicked three times before the screenshotHTMLLive
<style>body{font:15px/1.7 system-ui;margin:14px}button{font:inherit;padding:3px 9px}</style>
<div id="root"></div>
<script type="importmap">{"imports":{"react":"https://esm.sh/react@19.3.0",
"react-dom/client":"https://esm.sh/react-dom@19.3.0/client?external=react"}}</script>
<script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel" data-type="module">
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
function Counter() {
  const [count, setCount] = useState(0);   // 0 is the value for the first render only
  return (
    <p>You clicked {count} times{' '}
      <button onClick={() => setCount(count + 1)}>Click me</button></p>
  );
}
createRoot(document.getElementById('root')).render(<Counter />);
[300, 400, 500].forEach(t => setTimeout(() => document.querySelector('button').click(), t));
</script>
Browser output of Listing 2.14
Browser output of 14

The setter assigns nothing. It records that this component has a new value for that state slot and asks React to call the component again; the <p> above is the return value of the fourth call. A component may hold as many slots as it likes, and React tells them apart by the order the useState calls run in — which is why a hook may never sit inside a condition or a loop (The Rules of Hooks).

One behavior surprises people arriving from class components: if the value you pass is the one already stored, judged by Object.is, React skips the re-render entirely, where this.setState re-rendered anyway.