A button click, a form submission, or a video starting to play can change what an application displays. In React, handle a supported event by assigning a function to the corresponding JSX property: `<button onClick={onClick}>Increment</button>`. Choose the event, choose the element that dispatches it, and give React a function to call. React manages that listener as the component mounts and unmounts. section 8.1.1 section 8.1
Make a counter respond
With `const [count, setCount] = useState(0)`, define `const onClick = () => setCount(value => value + 1)` and render `<button onClick={onClick}>Increment</button>` beside the count. Passing `onClick` assigns the function; writing `onClick()` there would call it immediately instead. A short handler can also be inline: `onClick={() => setCount(value => value + 1)}`. Put a longer handler in a named variable to keep the JSX readable. section 8.1.1 section 8.2.1
A handler receives an event object even if it does not declare a parameter. Use `evt.target` to find the element that triggered the event or `evt.type` to distinguish event types. The same function can handle two counter buttons by checking which button was clicked, although separate handlers are equally valid. For a reusable button component, consider wrapping a callback if its caller should not receive the button’s event object. section 8.2.2 section 8.6
Place handlers where the intended interaction occurs:
- Use `onSubmit` on a form rather than only `onClick` on its button, so pressing Enter also works. Call `evt.preventDefault()` when submission must not perform the browser’s default page reload. section 8.4.2
- Use bubbling to handle events from several descendants at an ancestor. For example, `onFocus` on each fieldset and `onBlur` on the form can track which part of a contact form is active without listeners on every input. section 8.3
- Use an `onClickCapture` property when a handler must run during capture rather than the usual bubbling phase. Capture handlers are rarely needed. section 8.3.2
React’s JSX properties do not cover every event target or event type. To update a window-size display after a resize, attach a native listener inside an effect: `window.addEventListener("resize", onResize)`. Return a cleanup function that calls `window.removeEventListener("resize", onResize)`. The same approach can handle an unsupported event such as `transitionstart` on a DOM node obtained through a ref. Unlike a JSX listener, a manually attached listener is yours to remove. section 8.8.1 section 8.8.2
Listing 8.13 An expandable menu
import { useRef, useState, useEffect } from "react";
function Menu() {
const [isExpanded, setExpanded] = useState(false);
useEffect(() => {
if (!isExpanded) {
return;
}
const onWindowClick = () => setExpanded(false);
const onMenuClick = (evt) => evt.stopPropagation(); #1
const menu = menuRef.current; #2
window.addEventListener("pointerdown", onWindowClick);
menu.addEventListener("pointerdown", onMenuClick); #3
return () => {
window.removeEventListener( #4
"pointerdown", onWindowClick #4
); #4
menu.removeEventListener( #4
"pointerdown", onMenuClick #4
); #4
};
}, [isExpanded]);
const menuRef = useRef(); #5
return (
<main>
<button onClick={() => setExpanded(true)}>Show menu</button>
{isExpanded && (
<div
ref={menuRef} #6
style={{ border: "1px solid black", padding: "1em" }}
>
This is the menu
</div>
)}
</main>
);
}
function App() {
return <Menu />;
}
export default App;
An expandable menu combines a React button click with temporary native `pointerdown` listeners. Its menu listener stops the event from reaching the window listener, so clicking inside does not close the menu; cleanup removes both listeners. section 8.8.3





















