ClaimList: Factor out infinite-scroll and batch-resolve handling into an effect.
It's also possible to move the use of `useClaimListInfiniteScroll` into `claimList` itself, but opted to keep them separate for now so that `claimList` doesn't end up a bloated file like `claimListDiscover`.
This commit is contained in:
parent
a4bb276608
commit
51616956d4
2 changed files with 69 additions and 31 deletions
62
ui/effects/use-claimList-infinite-scroll.js
Normal file
62
ui/effects/use-claimList-infinite-scroll.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// @flow
|
||||
/**
|
||||
* Infinite-scroll and batch-resolving handling for `claimList` instances.
|
||||
*
|
||||
* By default, the list is "locked" during initial mount to have a stable
|
||||
* pagination, but can be disabled through the `disableListLock` parameter.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function useClaimListInfiniteScroll(
|
||||
allUris: Array<string>,
|
||||
doResolveUris: (uris: Array<string>, returnCachedClaims: boolean, resolveReposts: boolean) => void,
|
||||
pageSize: number = 30,
|
||||
disableListLock: boolean = false
|
||||
) {
|
||||
// Lock the full set of uris on mount, so we have a stable list for pagination.
|
||||
const [uris, setUris] = React.useState([]);
|
||||
|
||||
// Infinite-scroll handling. 'page' is 0-indexed.
|
||||
const [page, setPage] = React.useState(-1);
|
||||
const lastPage = Math.max(0, Math.ceil(allUris.length / pageSize) - 1);
|
||||
const [isLoadingPage, setIsLoadingPage] = React.useState(true);
|
||||
|
||||
async function resolveUris(uris) {
|
||||
return doResolveUris(uris, true, false);
|
||||
}
|
||||
|
||||
async function resolveNextPage(uris, currPage, pageSize) {
|
||||
const nextPage = currPage + 1;
|
||||
const nextUriBatch = uris.slice(nextPage * pageSize, (nextPage + 1) * pageSize);
|
||||
return resolveUris(nextUriBatch);
|
||||
}
|
||||
|
||||
function bumpPage() {
|
||||
if (page < lastPage) {
|
||||
setIsLoadingPage(true);
|
||||
resolveNextPage(uris, page, pageSize).finally(() => {
|
||||
setIsLoadingPage(false);
|
||||
setPage(page + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -- Initial mount: lock list and resolve first batch:
|
||||
React.useEffect(() => {
|
||||
setUris(allUris);
|
||||
resolveNextPage(allUris, -1, pageSize).finally(() => {
|
||||
setIsLoadingPage(false);
|
||||
setPage(0);
|
||||
});
|
||||
}, []);
|
||||
|
||||
// -- Optional: remove the locking behavior for whatever reason:
|
||||
React.useEffect(() => {
|
||||
if (disableListLock) {
|
||||
setUris(allUris);
|
||||
}
|
||||
}, [allUris]);
|
||||
|
||||
return { uris, page, isLoadingPage, bumpPage };
|
||||
}
|
|
@ -10,6 +10,7 @@ import Page from 'component/page';
|
|||
import Spinner from 'component/spinner';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import { SIDEBAR_SUBS_DISPLAYED } from 'constants/subscriptions';
|
||||
import useClaimListInfiniteScroll from 'effects/use-claimList-infinite-scroll';
|
||||
|
||||
function getFilteredUris(uris, filterQuery) {
|
||||
if (filterQuery) {
|
||||
|
@ -34,45 +35,20 @@ type Props = {
|
|||
|
||||
export default function ChannelsFollowingManage(props: Props) {
|
||||
const { subscribedChannelUris, lastActiveSubs, doResolveUris, doFetchLastActiveSubs } = props;
|
||||
|
||||
// The locked-on-mount full set of subscribed uris.
|
||||
const [uris, setUris] = React.useState([]);
|
||||
const { uris, page, isLoadingPage, bumpPage } = useClaimListInfiniteScroll(
|
||||
subscribedChannelUris,
|
||||
doResolveUris,
|
||||
FOLLOW_PAGE_SIZE
|
||||
);
|
||||
|
||||
// Filtered query and their uris.
|
||||
const [filterQuery, setFilterQuery] = React.useState('');
|
||||
const [filteredUris, setFilteredUris] = React.useState(null);
|
||||
|
||||
// Infinite-scroll handling. 'page' is 0-indexed.
|
||||
const [page, setPage] = React.useState(-1);
|
||||
const lastPage = Math.max(0, Math.ceil(uris.length / FOLLOW_PAGE_SIZE) - 1);
|
||||
const [loadingPage, setLoadingPage] = React.useState(false);
|
||||
|
||||
async function resolveUris(uris) {
|
||||
return doResolveUris(uris, true, false);
|
||||
}
|
||||
|
||||
async function resolveNextPage(uris, currPage, pageSize = FOLLOW_PAGE_SIZE) {
|
||||
const nextPage = currPage + 1;
|
||||
const nextUriBatch = uris.slice(nextPage * pageSize, (nextPage + 1) * pageSize);
|
||||
return resolveUris(nextUriBatch);
|
||||
}
|
||||
|
||||
function bumpPage() {
|
||||
if (page < lastPage) {
|
||||
setLoadingPage(true);
|
||||
resolveNextPage(uris, page).finally(() => {
|
||||
setLoadingPage(false);
|
||||
setPage(page + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
setUris(subscribedChannelUris);
|
||||
resolveNextPage(subscribedChannelUris, -1).finally(() => setPage(0));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps, (lock list on mount so it doesn't shift when unfollow)
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const filteredUris = getFilteredUris(uris, filterQuery);
|
||||
if (filteredUris) {
|
||||
|
@ -144,7 +120,7 @@ export default function ChannelsFollowingManage(props: Props) {
|
|||
onScrollBottom={bumpPage}
|
||||
page={page + 1}
|
||||
pageSize={FOLLOW_PAGE_SIZE}
|
||||
loading={loadingPage}
|
||||
loading={isLoadingPage}
|
||||
useLoadingSpinner
|
||||
/>
|
||||
</>
|
||||
|
|
Loading…
Reference in a new issue