Skip to content

Commit

Permalink
Fix usePagination stuck in isLoading
Browse files Browse the repository at this point in the history
Reviewed By: sammy-SC

Differential Revision: D66347840

fbshipit-source-id: 8c0d154444c519c4f0fe86d5908e4a63a809fe9a
  • Loading branch information
tyao1 authored and facebook-github-bot committed Nov 23, 2024
1 parent 6f76a2a commit e9e556c
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,19 @@ function expectFragmentResults(
renderSpy.mockClear();
}

function expectFragmentLastResult(expectedCall: {
data: $FlowFixMe,
isLoadingNext: boolean,
isLoadingPrevious: boolean,
hasNext: boolean,
hasPrevious: boolean,
}) {
TestRenderer.act(() => jest.runAllImmediates());
const lastIdx = renderSpy.mock.calls.length - 1;
assertCall(expectedCall, lastIdx);
renderSpy.mockClear();
}

function resolveQuery(payload: mixed) {
TestRenderer.act(() => {
dataSource.next(payload);
Expand Down Expand Up @@ -4312,6 +4325,152 @@ describe.each([
},
]);
});

it('resets `isLoading` to false, hen loadMore gets interrupted by refresh, and useLoadMore does not trigger a reset', () => {
RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX = true;
renderFragment();
expectFragmentResults([
{
data: initialUser,
isLoadingNext: false,
isLoadingPrevious: false,
hasNext: true,
hasPrevious: false,
},
]);

TestRenderer.act(() => {
loadNext(1);
});

expectFragmentResults([
{
data: initialUser,
isLoadingNext: true,
isLoadingPrevious: false,
hasNext: true,
hasPrevious: false,
},
]);
fetch.mockClear();

TestRenderer.act(() => {
refetch(
{
cursor: null,
},
{
fetchPolicy: 'network-only',
},
);
});

const refetchVariables = {
after: null,
before: null,
first: 1,
isViewerFriendLocal: false,
last: null,
orderby: ['name'],
scale: null,
id: '1',
};
paginationQuery = createOperationDescriptor(
gqlPaginationQuery,
refetchVariables,
{force: true},
);

const REFETCH_DATA = {
data: {
node: {
__typename: 'User',
id: '1',
name: 'Alice',
friends: {
edges: [
{
cursor: 'cursor:100',
node: {
__typename: 'User',
id: 'node:100',
name: 'name:node:100',
username: 'username:node:100',
},
},
],
pageInfo: {
endCursor: 'cursor:100',
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'cursor:100',
},
},
},
},
};
resolveQuery(REFETCH_DATA);

const expectedUser = {
id: '1',
name: 'Alice',
friends: {
edges: [
{
cursor: 'cursor:100',
node: {
__typename: 'User',
id: 'node:100',
name: 'name:node:100',
...createFragmentRef('node:100', paginationQuery),
},
},
],
pageInfo: {
endCursor: 'cursor:100',
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'cursor:100',
},
},
};

// loadNext gets interrupted by refetch, and `reset()` in useLoadMore triggers
expectFragmentLastResult({
data: expectedUser,
isLoadingNext: false,
isLoadingPrevious: false,
hasNext: true,
hasPrevious: false,
});

// loadNext gets interrupted by refetch, and `reset()` in useLoadMore doesn't trigger
// because fragmentIdentifier doesn't change
TestRenderer.act(() => {
loadNext(1);
});
TestRenderer.act(() => {
refetch(
{
cursor: null,
},
{
fetchPolicy: 'network-only',
},
);
});

resolveQuery(REFETCH_DATA);
expectFragmentLastResult({
data: expectedUser,
isLoadingNext: false,
isLoadingPrevious: false,
hasNext: true,
hasPrevious: false,
});

RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX = false;
});
});

describe('paginating @fetchable types', () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/react-relay/relay-hooks/usePaginationFragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const useRelayEnvironment = require('./useRelayEnvironment');
const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning');
const {useCallback, useDebugValue, useState} = require('react');
const {
RelayFeatureFlags,
getFragment,
getFragmentIdentifier,
getPaginationMetadata,
Expand Down Expand Up @@ -196,6 +197,9 @@ hook useLoadMore<TVariables: Variables>(
start: () => setIsLoadingMore(true),
complete: () => setIsLoadingMore(false),
error: () => setIsLoadingMore(false),
unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX
? () => setIsLoadingMore(false)
: undefined,
};
const handleReset = () => setIsLoadingMore(false);
const [loadMore, hasMore, disposeFetch] = useLoadMoreFunction<TVariables>({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const {
} = require('relay-runtime');
const {
ConnectionInterface,
RelayFeatureFlags,
getSelector,
getValueAtPath,
} = require('relay-runtime');
Expand Down Expand Up @@ -170,25 +171,25 @@ hook usePrefetchableForwardPaginationFragment_EXPERIMENTAL<
// to synchronously get the loading state to decide whether to load more
const isLoadingMoreRef = useRef(false);

const observer = useMemo(
() => ({
const observer = useMemo(() => {
function setIsLoadingFalse() {
isLoadingMoreRef.current = false;
setIsLoadingMore(false);
}
return {
start: () => {
isLoadingMoreRef.current = true;
// We want to make sure that `isLoadingMore` is updated immediately, to avoid
// product code triggering multiple `loadMore` calls
reallySetIsLoadingMore(true);
},
complete: () => {
isLoadingMoreRef.current = false;
setIsLoadingMore(false);
},
error: () => {
isLoadingMoreRef.current = false;
setIsLoadingMore(false);
},
}),
[setIsLoadingMore],
);
complete: setIsLoadingFalse,
error: setIsLoadingFalse,
unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX
? setIsLoadingFalse
: undefined,
};
}, [setIsLoadingMore]);
const handleReset = useCallback(() => {
if (!isRefetching) {
// Do not reset items count during refetching
Expand Down
4 changes: 4 additions & 0 deletions packages/relay-runtime/util/RelayFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ export type FeatureFlags = {
// hook allows you to manage a resource that is not tied to the component
// and replaces the need for multiple useEffects to manage the same resource.
ENABLE_RESOURCE_EFFECTS: boolean,

// Enable the fix for usePaginationFragment stucking in loading state
ENABLE_USE_PAGINATION_IS_LOADING_FIX: boolean,
};

const RelayFeatureFlags: FeatureFlags = {
Expand All @@ -87,6 +90,7 @@ const RelayFeatureFlags: FeatureFlags = {
ENABLE_ACTIVITY_COMPATIBILITY: false,
ENABLE_READ_TIME_RESOLVER_STORAGE_KEY_PREFIX: true,
ENABLE_RESOURCE_EFFECTS: false,
ENABLE_USE_PAGINATION_IS_LOADING_FIX: false,
};

module.exports = RelayFeatureFlags;

0 comments on commit e9e556c

Please sign in to comment.