useState
useState is a hook that adds local state to a function component. It returns a [value, setter] tuple. Calling the setter triggers a re-render with the new value.
Think of useState as a sticky note on the component's desk — the note persists between renders, but you must write a NEW note (new reference) to get the component to look at it again.
State updates are asynchronous and batched — calling setState three times in an event handler produces one re-render, not three. When the new state depends on the previous state, you must use the functional form: setState(prev => prev + 1). React uses Object.is to bail out of re-renders if the new value is the same reference as the old one. Initial state can be a lazy initializer function to avoid expensive computation on every render.
Under the hood, each useState call is stored as a node in a linked list on the fiber. The position in the list is determined by call order, which is why hooks cannot be called conditionally — it would shift the list and map values to wrong hooks. During concurrent rendering, React may render a component multiple times before committing; the state snapshot captured in each render is immutable, giving you a consistent view even if more updates arrive. The batching behavior was expanded in React 18 to cover all contexts (setTimeout, promises, native event handlers), not just React synthetic events as in React 17.
useState gives function components local state. It returns a value and a setter. Updates are batched and asynchronous — React may combine multiple setState calls into a single re-render. When new state depends on old state, I always use the functional updater form. React 18 batches updates everywhere, not just in event handlers.
Setting state with the same object reference (e.g., mutating an array and calling setState with it) won't trigger a re-render because React uses Object.is comparison. You must create a new reference: setState([...arr]).