Use `useRef` when a component needs to remember a value without displaying that value. The hook returns a reference object with a mutable `current` property. That value persists across renders, but changing it does not trigger a re-render. Use `useState` instead when a change should update what the component displays. section 7.1.3
Remember the previous click
A counter should increment only when two clicks occur within 300 milliseconds: ```jsx import { useRef, useState } from "react"; function DoubleClickCounter() { const [count, setCount] = useState(0); const lastClickTime = useRef(null); function handleClick() { const now = Date.now(); if (now - lastClickTime.current < 300) { setCount(value => value + 1); } else { lastClickTime.current = now; } } return <button onClick={handleClick}>Count: {count}</button>; } ``` The first click records a time without changing the displayed count. A qualifying second click updates state and re-renders the button. Storing the click time in state would cause an unnecessary render. section 7.1.3
A ref can also point to a DOM element. Attach it with the element’s `ref` prop, then access the element through `ref.current` when you need to work with it. section 7.1.3
Focus an input
```jsx import { useEffect, useRef } from "react"; function AutoFocusInput() { const inputRef = useRef(); useEffect(() => inputRef.current.focus(), []); return <input ref={inputRef} />; } ``` Here, the ref gives the effect access to the rendered input. section 7.1.3
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 uses a ref to reach its DOM node. A pointer-down listener on the menu stops events from reaching a window listener, so clicks outside close the menu while clicks inside do not. section 8.8.3


