Skip to content

Commit e9e556c

Browse files
tyao1facebook-github-bot
authored andcommitted
Fix usePagination stuck in isLoading
Reviewed By: sammy-SC Differential Revision: D66347840 fbshipit-source-id: 8c0d154444c519c4f0fe86d5908e4a63a809fe9a
1 parent 6f76a2a commit e9e556c

File tree

4 files changed

+181
-13
lines changed

4 files changed

+181
-13
lines changed

packages/react-relay/relay-hooks/__tests__/usePaginationFragment-test.js

+159
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,19 @@ function expectFragmentResults(
176176
renderSpy.mockClear();
177177
}
178178

179+
function expectFragmentLastResult(expectedCall: {
180+
data: $FlowFixMe,
181+
isLoadingNext: boolean,
182+
isLoadingPrevious: boolean,
183+
hasNext: boolean,
184+
hasPrevious: boolean,
185+
}) {
186+
TestRenderer.act(() => jest.runAllImmediates());
187+
const lastIdx = renderSpy.mock.calls.length - 1;
188+
assertCall(expectedCall, lastIdx);
189+
renderSpy.mockClear();
190+
}
191+
179192
function resolveQuery(payload: mixed) {
180193
TestRenderer.act(() => {
181194
dataSource.next(payload);
@@ -4312,6 +4325,152 @@ describe.each([
43124325
},
43134326
]);
43144327
});
4328+
4329+
it('resets `isLoading` to false, hen loadMore gets interrupted by refresh, and useLoadMore does not trigger a reset', () => {
4330+
RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX = true;
4331+
renderFragment();
4332+
expectFragmentResults([
4333+
{
4334+
data: initialUser,
4335+
isLoadingNext: false,
4336+
isLoadingPrevious: false,
4337+
hasNext: true,
4338+
hasPrevious: false,
4339+
},
4340+
]);
4341+
4342+
TestRenderer.act(() => {
4343+
loadNext(1);
4344+
});
4345+
4346+
expectFragmentResults([
4347+
{
4348+
data: initialUser,
4349+
isLoadingNext: true,
4350+
isLoadingPrevious: false,
4351+
hasNext: true,
4352+
hasPrevious: false,
4353+
},
4354+
]);
4355+
fetch.mockClear();
4356+
4357+
TestRenderer.act(() => {
4358+
refetch(
4359+
{
4360+
cursor: null,
4361+
},
4362+
{
4363+
fetchPolicy: 'network-only',
4364+
},
4365+
);
4366+
});
4367+
4368+
const refetchVariables = {
4369+
after: null,
4370+
before: null,
4371+
first: 1,
4372+
isViewerFriendLocal: false,
4373+
last: null,
4374+
orderby: ['name'],
4375+
scale: null,
4376+
id: '1',
4377+
};
4378+
paginationQuery = createOperationDescriptor(
4379+
gqlPaginationQuery,
4380+
refetchVariables,
4381+
{force: true},
4382+
);
4383+
4384+
const REFETCH_DATA = {
4385+
data: {
4386+
node: {
4387+
__typename: 'User',
4388+
id: '1',
4389+
name: 'Alice',
4390+
friends: {
4391+
edges: [
4392+
{
4393+
cursor: 'cursor:100',
4394+
node: {
4395+
__typename: 'User',
4396+
id: 'node:100',
4397+
name: 'name:node:100',
4398+
username: 'username:node:100',
4399+
},
4400+
},
4401+
],
4402+
pageInfo: {
4403+
endCursor: 'cursor:100',
4404+
hasNextPage: true,
4405+
hasPreviousPage: false,
4406+
startCursor: 'cursor:100',
4407+
},
4408+
},
4409+
},
4410+
},
4411+
};
4412+
resolveQuery(REFETCH_DATA);
4413+
4414+
const expectedUser = {
4415+
id: '1',
4416+
name: 'Alice',
4417+
friends: {
4418+
edges: [
4419+
{
4420+
cursor: 'cursor:100',
4421+
node: {
4422+
__typename: 'User',
4423+
id: 'node:100',
4424+
name: 'name:node:100',
4425+
...createFragmentRef('node:100', paginationQuery),
4426+
},
4427+
},
4428+
],
4429+
pageInfo: {
4430+
endCursor: 'cursor:100',
4431+
hasNextPage: true,
4432+
hasPreviousPage: false,
4433+
startCursor: 'cursor:100',
4434+
},
4435+
},
4436+
};
4437+
4438+
// loadNext gets interrupted by refetch, and `reset()` in useLoadMore triggers
4439+
expectFragmentLastResult({
4440+
data: expectedUser,
4441+
isLoadingNext: false,
4442+
isLoadingPrevious: false,
4443+
hasNext: true,
4444+
hasPrevious: false,
4445+
});
4446+
4447+
// loadNext gets interrupted by refetch, and `reset()` in useLoadMore doesn't trigger
4448+
// because fragmentIdentifier doesn't change
4449+
TestRenderer.act(() => {
4450+
loadNext(1);
4451+
});
4452+
TestRenderer.act(() => {
4453+
refetch(
4454+
{
4455+
cursor: null,
4456+
},
4457+
{
4458+
fetchPolicy: 'network-only',
4459+
},
4460+
);
4461+
});
4462+
4463+
resolveQuery(REFETCH_DATA);
4464+
expectFragmentLastResult({
4465+
data: expectedUser,
4466+
isLoadingNext: false,
4467+
isLoadingPrevious: false,
4468+
hasNext: true,
4469+
hasPrevious: false,
4470+
});
4471+
4472+
RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX = false;
4473+
});
43154474
});
43164475

43174476
describe('paginating @fetchable types', () => {

packages/react-relay/relay-hooks/usePaginationFragment.js

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const useRelayEnvironment = require('./useRelayEnvironment');
2828
const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning');
2929
const {useCallback, useDebugValue, useState} = require('react');
3030
const {
31+
RelayFeatureFlags,
3132
getFragment,
3233
getFragmentIdentifier,
3334
getPaginationMetadata,
@@ -196,6 +197,9 @@ hook useLoadMore<TVariables: Variables>(
196197
start: () => setIsLoadingMore(true),
197198
complete: () => setIsLoadingMore(false),
198199
error: () => setIsLoadingMore(false),
200+
unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX
201+
? () => setIsLoadingMore(false)
202+
: undefined,
199203
};
200204
const handleReset = () => setIsLoadingMore(false);
201205
const [loadMore, hasMore, disposeFetch] = useLoadMoreFunction<TVariables>({

packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js

+14-13
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const {
3838
} = require('relay-runtime');
3939
const {
4040
ConnectionInterface,
41+
RelayFeatureFlags,
4142
getSelector,
4243
getValueAtPath,
4344
} = require('relay-runtime');
@@ -170,25 +171,25 @@ hook usePrefetchableForwardPaginationFragment_EXPERIMENTAL<
170171
// to synchronously get the loading state to decide whether to load more
171172
const isLoadingMoreRef = useRef(false);
172173

173-
const observer = useMemo(
174-
() => ({
174+
const observer = useMemo(() => {
175+
function setIsLoadingFalse() {
176+
isLoadingMoreRef.current = false;
177+
setIsLoadingMore(false);
178+
}
179+
return {
175180
start: () => {
176181
isLoadingMoreRef.current = true;
177182
// We want to make sure that `isLoadingMore` is updated immediately, to avoid
178183
// product code triggering multiple `loadMore` calls
179184
reallySetIsLoadingMore(true);
180185
},
181-
complete: () => {
182-
isLoadingMoreRef.current = false;
183-
setIsLoadingMore(false);
184-
},
185-
error: () => {
186-
isLoadingMoreRef.current = false;
187-
setIsLoadingMore(false);
188-
},
189-
}),
190-
[setIsLoadingMore],
191-
);
186+
complete: setIsLoadingFalse,
187+
error: setIsLoadingFalse,
188+
unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX
189+
? setIsLoadingFalse
190+
: undefined,
191+
};
192+
}, [setIsLoadingMore]);
192193
const handleReset = useCallback(() => {
193194
if (!isRefetching) {
194195
// Do not reset items count during refetching

packages/relay-runtime/util/RelayFeatureFlags.js

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export type FeatureFlags = {
6363
// hook allows you to manage a resource that is not tied to the component
6464
// and replaces the need for multiple useEffects to manage the same resource.
6565
ENABLE_RESOURCE_EFFECTS: boolean,
66+
67+
// Enable the fix for usePaginationFragment stucking in loading state
68+
ENABLE_USE_PAGINATION_IS_LOADING_FIX: boolean,
6669
};
6770

6871
const RelayFeatureFlags: FeatureFlags = {
@@ -87,6 +90,7 @@ const RelayFeatureFlags: FeatureFlags = {
8790
ENABLE_ACTIVITY_COMPATIBILITY: false,
8891
ENABLE_READ_TIME_RESOLVER_STORAGE_KEY_PREFIX: true,
8992
ENABLE_RESOURCE_EFFECTS: false,
93+
ENABLE_USE_PAGINATION_IS_LOADING_FIX: false,
9094
};
9195

9296
module.exports = RelayFeatureFlags;

0 commit comments

Comments
 (0)