A layout route often holds something its child routes need — a selected filter, an editing flag, a setter. <Outlet> already has the slot: pass a context prop, and whichever child is rendered reads it back with useOutletContext().
function ReportLayout() {
const [range, setRange] = useState('month');
return <div>
<select value={range} onChange={(e) => setRange(e.target.value)}>
<option value="week">This week</option><option value="month">This month</option></select>
<Outlet context={{ range, setRange }} /></div>;
}
const Revenue = () => <p>Revenue for: {useOutletContext().range}</p>;ReportLayout mounts once and owns the state, so switching between child routes changes only what fills the outlet: the selected range survives the navigation, because the parent is a route, mounted as long as the URL stays inside it.
Unlike every other hook in this section, useOutletContext() does not require a data router; <Outlet context> works identically inside a declarative <BrowserRouter> tree. In TypeScript, have the layout export a typed hook — export const useRange = () => useOutletContext<RangeContext>(). Keep the value small: it is plain React 7,897 context (Context Performance Pitfalls).