Skip to content

Commit 2e01ae7

Browse files
committed
Add code example
1 parent d34d3ce commit 2e01ae7

1 file changed

Lines changed: 190 additions & 0 deletions

File tree

src/content/reference/react/Suspense.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,196 @@ Without a framework, you can read a Promise with `use` directly, as long as the
229229

230230
</Note>
231231

232+
For example, both boundaries below are set up identically. The one on the left activates because its content reads a Promise with `use`, so it shows the `fallback` while loading. The one on the right fetches the same data inside an Effect, which Suspense can't detect, so its `fallback` never appears and the albums simply show up once the fetch resolves:
233+
234+
<Sandpack>
235+
236+
```js
237+
import { Suspense } from 'react';
238+
import Albums from './Albums.js';
239+
import EffectAlbums from './EffectAlbums.js';
240+
241+
export default function App() {
242+
return (
243+
<div className="panels">
244+
<section className="panel">
245+
<h2>Reads a Promise with use</h2>
246+
<Suspense fallback={<Loading />}>
247+
<Albums artistId="the-beatles" />
248+
</Suspense>
249+
</section>
250+
<section className="panel">
251+
<h2>Fetches in an Effect</h2>
252+
<Suspense fallback={<Loading />}>
253+
<EffectAlbums artistId="the-beatles" />
254+
</Suspense>
255+
</section>
256+
</div>
257+
);
258+
}
259+
260+
function Loading() {
261+
return <p>🌀 Loading...</p>;
262+
}
263+
```
264+
265+
```js src/Albums.js active
266+
import { use } from 'react';
267+
import { fetchData } from './data.js';
268+
269+
export default function Albums({ artistId }) {
270+
// Reading the Promise with `use` activates
271+
// the Suspense boundary while it loads.
272+
const albums = use(fetchData(`/${artistId}/albums`));
273+
return (
274+
<ul>
275+
{albums.map(album => (
276+
<li key={album.id}>
277+
{album.title} ({album.year})
278+
</li>
279+
))}
280+
</ul>
281+
);
282+
}
283+
```
284+
285+
```js src/EffectAlbums.js
286+
import { useState, useEffect } from 'react';
287+
import { fetchData } from './data.js';
288+
289+
export default function EffectAlbums({ artistId }) {
290+
const [albums, setAlbums] = useState([]);
291+
292+
useEffect(() => {
293+
let active = true;
294+
fetchData(`/${artistId}/albums`).then(result => {
295+
if (active) {
296+
setAlbums(result);
297+
}
298+
});
299+
return () => {
300+
active = false;
301+
};
302+
}, [artistId]);
303+
304+
// Suspense can't see this fetch, so its fallback never
305+
// shows. The list stays empty until the data arrives.
306+
return (
307+
<ul>
308+
{albums.map(album => (
309+
<li key={album.id}>
310+
{album.title} ({album.year})
311+
</li>
312+
))}
313+
</ul>
314+
);
315+
}
316+
```
317+
318+
```js src/data.js hidden
319+
// Note: the way you would do data fetching depends on
320+
// the framework that you use together with Suspense.
321+
// Normally, the caching logic would be inside a framework.
322+
323+
let cache = new Map();
324+
325+
export function fetchData(url) {
326+
if (!cache.has(url)) {
327+
cache.set(url, getData(url));
328+
}
329+
return cache.get(url);
330+
}
331+
332+
async function getData(url) {
333+
if (url === '/the-beatles/albums') {
334+
return await getAlbums();
335+
} else {
336+
throw Error('Not implemented');
337+
}
338+
}
339+
340+
async function getAlbums() {
341+
// Add a fake delay to make waiting noticeable.
342+
await new Promise(resolve => {
343+
setTimeout(resolve, 3000);
344+
});
345+
346+
return [{
347+
id: 13,
348+
title: 'Let It Be',
349+
year: 1970
350+
}, {
351+
id: 12,
352+
title: 'Abbey Road',
353+
year: 1969
354+
}, {
355+
id: 11,
356+
title: 'Yellow Submarine',
357+
year: 1969
358+
}, {
359+
id: 10,
360+
title: 'The Beatles',
361+
year: 1968
362+
}, {
363+
id: 9,
364+
title: 'Magical Mystery Tour',
365+
year: 1967
366+
}, {
367+
id: 8,
368+
title: 'Sgt. Pepper\'s Lonely Hearts Club Band',
369+
year: 1967
370+
}, {
371+
id: 7,
372+
title: 'Revolver',
373+
year: 1966
374+
}, {
375+
id: 6,
376+
title: 'Rubber Soul',
377+
year: 1965
378+
}, {
379+
id: 5,
380+
title: 'Help!',
381+
year: 1965
382+
}, {
383+
id: 4,
384+
title: 'Beatles For Sale',
385+
year: 1964
386+
}, {
387+
id: 3,
388+
title: 'A Hard Day\'s Night',
389+
year: 1964
390+
}, {
391+
id: 2,
392+
title: 'With The Beatles',
393+
year: 1963
394+
}, {
395+
id: 1,
396+
title: 'Please Please Me',
397+
year: 1963
398+
}];
399+
}
400+
```
401+
402+
```css
403+
.panels {
404+
display: flex;
405+
gap: 20px;
406+
}
407+
408+
.panel {
409+
flex: 1;
410+
padding: 0 15px;
411+
border: 1px solid #eee;
412+
border-radius: 8px;
413+
}
414+
415+
.panel h2 {
416+
font-size: 1rem;
417+
}
418+
```
419+
420+
</Sandpack>
421+
232422
---
233423

234424
### Revealing content together at once {/*revealing-content-together-at-once*/}

0 commit comments

Comments
 (0)