Infinite Feed
A feed that never ends has to fetch while the viewer watches: early enough that the next post is already there, with something to show while a page is on its way or has failed, and without a request left running after the feed is gone.
Try it
Every version imports ./api, which stands in for your backend: fetchPosts(page, signal) returns one page of posts and stops when the signal aborts. Replace it with a call to your API, and drop failNextRequest, which only drives the demo's failure switch.
import { createSignal } from '@reelkit/core';
import { cdnUrl } from '@reelkit/example-data';
// Stands in for your backend. The recipe only relies on the signature of
// `fetchPosts`: a page number in, a page of posts out, cancellable through an
// AbortSignal.
export interface Post {
id: string;
title: string;
image: string;
}
const kPageSize = 6;
const kDelayMs = 800;
const kImages = Array.from(
{ length: 9 },
(_, i) => `samples/images/image-${String(i + 1).padStart(2, '0')}.jpg`,
);
/**
* Demo switch: while on, the next request fails, so the error slide can be
* seen. A signal, so the switch shows when a request has used it up. Only the
* demo on this page uses it: delete it, and the `@reelkit/core` import with
* it, when you replace `fetchPosts` with your API.
*/
export const failNextRequest = createSignal(false);
export function fetchPosts(page: number, signal: AbortSignal): Promise<Post[]> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
if (failNextRequest.value) {
failNextRequest.value = false;
reject(new Error('The feed could not be loaded.'));
return;
}
resolve(
Array.from({ length: kPageSize }, (_, i) => {
const n = page * kPageSize + i;
return {
id: `post-${n}`,
title: `Post ${n + 1}`,
image: cdnUrl(kImages[n % kImages.length]),
};
}),
);
}, kDelayMs);
signal.addEventListener(
'abort',
() => {
clearTimeout(timer);
reject(signal.reason);
},
{ once: true },
);
});
}The sample media works only on reelkit.dev
cdnUrl builds links to cdn.reelkit.dev, which serves its files only to the ReelKit sites. In your app those images fail to load, so point image at your own media before you copy this file.
Swipe up or press ↓: a new page arrives three posts before the end. Press "Fail next request" to see the error slide and its Retry.
Why it works
- The count grows, the slides do not.
countis the number of posts plus one, and only three slides are ever in the DOM, so a feed of thousands costs the same as a feed of ten. See virtualization. - The last slide is the status. The extra slide past the posts shows "Loading…" while a page is on its way and the error with Retry when it failed, so the viewer never swipes into nothing. It is one more case in the itemBuilder, which renders whatever the index stands for.
- Fetch ahead, from the slide change.
afterChangeasks for the next page once the viewer is three posts from the end. A failed page waits for Retry, so swiping back and forth does not repeat a failing request. The callback is listed with the other events for React, Vue, and Angular. - Keys follow the posts.
keyExtractorreturns each post's id, so a slide keeps its element when a page lands behind it instead of being rebuilt from its index. It is a prop of React, Vue, and Angular alike. - Images load before their slide. A slide further down is not mounted yet, because only the visible range is, as virtualization explains. So each new page's images are requested as soon as the page arrives and come from the browser cache when their slide mounts.
- Keys and wheel are off on purpose.
enableNavKeyslistens on the whole window andenableWheelholds the page's scroll while the pointer is over the feed. Both suit a feed that fills the screen and fight a page that holds one, as this one does, so here they stay off and two buttons callprev()andnext()on the Reel API instead. Swiping works either way. - Nothing outlives the feed. Each request carries an
AbortController, aborted when the feed unmounts, so a late response never writes into a feed that is gone.
Next Steps
- Grid to Player - open the full-screen player from a thumbnail grid and come back to where you were
- Framework Guide - every Reel prop and pattern behind this recipeFramework Guide - every Reel prop and pattern behind this recipeFramework Guide - every Reel prop and pattern behind this recipe