Deferring the Initial Render

Passing a second argument to useDeferredValue only changes what comes back on a component's very first render. Below, items starts out empty and is replaced with 200 real entries from inside an effect right after mount; useDeferredValue(items, ['Loading...']) shows that placeholder array for the true first paint, then follows the usual deferred path once the real data arrives.

The list briefly reads "Loading..." the instant this mounts, then swaps in all 200 rows shortly after (rendering each row is artificially slowed down to make the swap visible). Had the second argument been left out, that very first render would instead have shown items itself — here, the empty array it started as.
RESETRUNFULL
<!DOCTYPE html><html><head>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head><body>
<div></div>
<script type="text/babel">
function Row({ text }) {
  const start = performance.now();
  while (performance.now() - start < 1) {} // simulate an expensive row
  return <li>{text}</li>;
}
function List({ items }) {
  return <ul>{items.map((text, i) => <Row key={i} text={text} />)}</ul>;
}
function App() {
  const [items, setItems] = React.useState([]);
  React.useEffect(() => {
    const bigList = [];
    for (let i = 0; i < 200; i++) bigList.push('Item #' + i);
    setItems(bigList);
  }, []);
  const deferredItems = React.useDeferredValue(items, ['Loading...']);
  return <List items={deferredItems} />;
}
const root = ReactDOM.createRoot(document.querySelector("div"));
root.render(<App/>);
</script>
</body></html>