UNPKG

react-ketting

Version:
117 lines 4.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.usePagedCollection = exports.useInfiniteCollection = void 0; const react_1 = require("react"); const use_read_resource_1 = require("./use-read-resource"); /** * The useInfiniteCollection hook works similar to useCollection, but has the * ability to load in additional pages of items. * * For this to work, the API needs to expose a "next" link on the collection. * As long as there are "next" links, more pages can be loaded in. * * Additional items from collection pages will be appended to "items", * allowing frontends to build 'infinite scroll' features. * * Example call: * * <pre> * const { * loading, * error, * items, * } = useInfiniteResource<Article>(resource); * </pre> * * The resource may be passed as a Resource object, a Promise<Resource>, or a * uri string. * * Returned properties: * * * loading - will be true every time we're going to the server and fetch a * a new page. * * error - Will be null or an error object. * * items - Will contain an array of resources, each typed Resource<T> where * T is the passed generic argument. * * hasNextPage - Will be true if the server has another page. * * loadNextPage - Loads the next page, and appends the new items to the * items array. */ function useInfiniteCollection(resourceLike, options) { var _a, _b; const rel = (options === null || options === void 0 ? void 0 : options.rel) || 'item'; const [items, setItems] = (0, react_1.useState)([]); // Are there more pages? const nextPageResource = (0, react_1.useRef)(null); const error = (0, react_1.useRef)(null); // Are we currently loading a 'next page'. This is used to avoid race conditions const [loading, setLoading] = (0, react_1.useState)(false); // This is the 'base collection' const bc = (0, use_read_resource_1.useReadResource)(resourceLike, { refreshOnStale: options === null || options === void 0 ? void 0 : options.refreshOnStale, // This header will be included on the first, uncached fetch. // This may be helpful to the server and instruct it to embed // all collection members in that initial fetch. initialGetRequestHeaders: { Prefer: 'transclude=' + rel, } }); (0, react_1.useEffect)(() => { if (!bc.loading) { // The 'base collection' has stopped loading, so lets set the first page. setItems(bc.resourceState.followAll(rel)); nextPageResource.current = bc.resourceState.links.has('next') ? bc.resourceState.follow('next') : null; setLoading(false); } }, [bc.resourceState]); let loadNextPageCalled = false; const loadNextPage = async () => { if (!nextPageResource.current) { console.warn('loadNextPage was called, but there was no next page'); return; } if (loadNextPageCalled) { console.warn('You called loadNextPage(), but it was an old copy. You should not memoize or store a reference to this function, but instead always use the one that was returned last. We ignored this call'); return; } loadNextPageCalled = true; // We are currently loading a new page setLoading(true); try { const nextPageState = await nextPageResource.current.get({ headers: { Prefer: 'transclude=' + rel, } }); // Set up the next page. nextPageResource.current = nextPageState.links.has('next') ? nextPageState.follow('next') : null; // Add new resources to page data setItems([ ...items, ...nextPageState.followAll(rel) ]); } catch (err) { error.current = err; } setLoading(false); }; return { loading: bc.loading || loading, error: (_b = (_a = bc.error) !== null && _a !== void 0 ? _a : error.current) !== null && _b !== void 0 ? _b : null, items, hasNextPage: nextPageResource.current !== null, loadNextPage, }; } exports.useInfiniteCollection = useInfiniteCollection; /** * usePagedCollection is the deprecated old name for useInfiniteCollection * * @deprecated Rename to useInfiniteCollection */ function usePagedCollection(resourceLike, options) { return useInfiniteCollection(resourceLike, options); } exports.usePagedCollection = usePagedCollection; //# sourceMappingURL=use-infinite-collection.js.map