react-relay 15.0.0 → 16.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/ReactRelayContext.js +1 -1
- package/ReactRelayQueryFetcher.js.flow +1 -5
- package/ReactRelayQueryRenderer.js.flow +9 -36
- package/ReactRelayTypes.js.flow +1 -0
- package/buildReactRelayContainer.js.flow +3 -1
- package/hooks.js +1 -1
- package/index.js +1 -1
- package/legacy.js +1 -1
- package/lib/ReactRelayContainerUtils.js +0 -11
- package/lib/ReactRelayContext.js +0 -11
- package/lib/ReactRelayFragmentContainer.js +6 -78
- package/lib/ReactRelayFragmentMockRenderer.js +0 -11
- package/lib/ReactRelayLocalQueryRenderer.js +0 -17
- package/lib/ReactRelayPaginationContainer.js +5 -208
- package/lib/ReactRelayQueryFetcher.js +2 -51
- package/lib/ReactRelayQueryRenderer.js +6 -94
- package/lib/ReactRelayQueryRendererContext.js +0 -11
- package/lib/ReactRelayRefetchContainer.js +5 -91
- package/lib/ReactRelayTestMocker.js +9 -85
- package/lib/ReactRelayTypes.js +0 -11
- package/lib/RelayContext.js +0 -21
- package/lib/assertFragmentMap.js +0 -15
- package/lib/buildReactRelayContainer.js +0 -19
- package/lib/getRootVariablesForFragments.js +0 -14
- package/lib/hooks.js +0 -15
- package/lib/index.js +0 -17
- package/lib/isRelayEnvironment.js +1 -18
- package/lib/jest-react/enqueueTask.js +0 -20
- package/lib/jest-react/internalAct.js +0 -38
- package/lib/legacy.js +0 -15
- package/lib/multi-actor/ActorChange.js +0 -11
- package/lib/multi-actor/index.js +0 -11
- package/lib/multi-actor/useRelayActorEnvironment.js +0 -11
- package/lib/relay-hooks/EntryPointContainer.react.js +0 -11
- package/lib/relay-hooks/EntryPointTypes.flow.js +1 -14
- package/lib/relay-hooks/FragmentResource.js +76 -132
- package/lib/relay-hooks/HooksImplementation.js +1 -12
- package/lib/relay-hooks/InternalLogger.js +0 -11
- package/lib/relay-hooks/LRUCache.js +0 -22
- package/lib/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js +0 -18
- package/lib/relay-hooks/MatchContainer.js +0 -94
- package/lib/relay-hooks/NestedRelayEntryPointBuilderUtils.js +9 -0
- package/lib/relay-hooks/ProfilerContext.js +0 -15
- package/lib/relay-hooks/QueryResource.js +2 -68
- package/lib/relay-hooks/RelayEnvironmentProvider.js +0 -11
- package/lib/relay-hooks/SuspenseResource.js +0 -34
- package/lib/relay-hooks/{react-cache/readFragmentInternal_REACT_CACHE.js → experimental/readFragmentInternal_EXPERIMENTAL.js} +5 -29
- package/lib/relay-hooks/{react-cache/useFragmentInternal_REACT_CACHE.js → experimental/useFragmentInternal_EXPERIMENTAL.js} +35 -100
- package/lib/relay-hooks/{react-cache/useFragment_REACT_CACHE.js → experimental/useFragment_EXPERIMENTAL.js} +1 -16
- package/lib/relay-hooks/{react-cache/usePaginationFragment_REACT_CACHE.js → experimental/usePaginationFragment_EXPERIMENTAL.js} +2 -24
- package/lib/relay-hooks/{react-cache/useRefetchableFragmentInternal_REACT_CACHE.js → experimental/useRefetchableFragmentInternal_EXPERIMENTAL.js} +14 -98
- package/lib/relay-hooks/{react-cache/useRefetchableFragment_REACT_CACHE.js → experimental/useRefetchableFragment_EXPERIMENTAL.js} +1 -15
- package/lib/relay-hooks/loadEntryPoint.js +1 -24
- package/lib/relay-hooks/loadQuery.js +2 -106
- package/lib/relay-hooks/preloadQuery_DEPRECATED.js +2 -27
- package/lib/relay-hooks/prepareEntryPoint_DEPRECATED.js +0 -13
- package/lib/relay-hooks/useBlockingPaginationFragment.js +0 -42
- package/lib/relay-hooks/useClientQuery.js +0 -18
- package/lib/relay-hooks/useEntryPointLoader.js +0 -69
- package/lib/relay-hooks/useFetchTrackingRef.js +0 -26
- package/lib/relay-hooks/useFragment.js +0 -17
- package/lib/relay-hooks/useFragmentNode.js +2 -32
- package/lib/relay-hooks/useIsMountedRef.js +0 -11
- package/lib/relay-hooks/useIsOperationNodeActive.js +0 -11
- package/lib/relay-hooks/useIsParentQueryActive.js +0 -11
- package/lib/relay-hooks/useLazyLoadQuery.js +0 -18
- package/lib/relay-hooks/useLazyLoadQueryNode.js +12 -37
- package/lib/relay-hooks/useLoadMoreFunction.js +9 -34
- package/lib/relay-hooks/useMemoOperationDescriptor.js +0 -11
- package/lib/relay-hooks/useMemoVariables.js +0 -17
- package/lib/relay-hooks/useMutation.js +0 -11
- package/lib/relay-hooks/usePaginationFragment.js +1 -26
- package/lib/relay-hooks/usePreloadedQuery.js +0 -27
- package/lib/relay-hooks/useQueryLoader.js +0 -74
- package/lib/relay-hooks/useRefetchableFragment.js +0 -16
- package/lib/relay-hooks/useRefetchableFragmentNode.js +14 -97
- package/lib/relay-hooks/useRelayEnvironment.js +0 -11
- package/lib/relay-hooks/useStaticFragmentNodeWarning.js +0 -15
- package/lib/relay-hooks/useSubscribeToInvalidationState.js +0 -25
- package/lib/relay-hooks/useSubscription.js +0 -15
- package/lib/relay-hooks/useUnsafeRef_DEPRECATED.js +0 -17
- package/package.json +2 -2
- package/react-relay-hooks.js +2 -2
- package/react-relay-hooks.min.js +2 -2
- package/react-relay-legacy.js +2 -2
- package/react-relay-legacy.min.js +2 -2
- package/react-relay.js +2 -2
- package/react-relay.min.js +2 -2
- package/relay-hooks/EntryPointContainer.react.js.flow +5 -0
- package/relay-hooks/EntryPointTypes.flow.js.flow +34 -35
- package/relay-hooks/FragmentResource.js.flow +114 -26
- package/relay-hooks/HooksImplementation.js.flow +3 -1
- package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +4 -2
- package/relay-hooks/NestedRelayEntryPointBuilderUtils.js.flow +51 -0
- package/relay-hooks/__flowtests__/EntryPointTypes/NestedEntrypoints-flowtest.js.flow +7 -5
- package/relay-hooks/__flowtests__/useBlockingPaginationFragment-flowtest.js.flow +5 -0
- package/relay-hooks/__flowtests__/usePaginationFragment-flowtest.js.flow +5 -0
- package/relay-hooks/__flowtests__/useRefetchableFragment-flowtest.js.flow +2 -0
- package/relay-hooks/{react-cache/readFragmentInternal_REACT_CACHE.js.flow → experimental/readFragmentInternal_EXPERIMENTAL.js.flow} +4 -3
- package/relay-hooks/{react-cache/useFragmentInternal_REACT_CACHE.js.flow → experimental/useFragmentInternal_EXPERIMENTAL.js.flow} +32 -14
- package/relay-hooks/{react-cache/useFragment_REACT_CACHE.js.flow → experimental/useFragment_EXPERIMENTAL.js.flow} +4 -10
- package/relay-hooks/{react-cache/usePaginationFragment_REACT_CACHE.js.flow → experimental/usePaginationFragment_EXPERIMENTAL.js.flow} +30 -59
- package/relay-hooks/{react-cache/useRefetchableFragmentInternal_REACT_CACHE.js.flow → experimental/useRefetchableFragmentInternal_EXPERIMENTAL.js.flow} +30 -23
- package/relay-hooks/experimental/useRefetchableFragment_EXPERIMENTAL.js.flow +49 -0
- package/relay-hooks/loadEntryPoint.js.flow +4 -2
- package/relay-hooks/loadQuery.js.flow +21 -1
- package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +4 -2
- package/relay-hooks/useBlockingPaginationFragment.js.flow +10 -17
- package/relay-hooks/useClientQuery.js.flow +2 -2
- package/relay-hooks/useFragmentNode.js.flow +2 -2
- package/relay-hooks/useLazyLoadQueryNode.js.flow +17 -1
- package/relay-hooks/useLoadMoreFunction.js.flow +15 -9
- package/relay-hooks/useMutation.js.flow +26 -9
- package/relay-hooks/usePaginationFragment.js.flow +7 -15
- package/relay-hooks/useQueryLoader.js.flow +2 -8
- package/relay-hooks/useRefetchableFragment.js.flow +14 -16
- package/relay-hooks/useRefetchableFragmentNode.js.flow +33 -20
- package/lib/relay-hooks/react-cache/RelayReactCache.js +0 -32
- package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +0 -290
- package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +0 -49
- package/lib/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js +0 -110
- package/relay-hooks/react-cache/RelayReactCache.js.flow +0 -40
- package/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js.flow +0 -430
- package/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js.flow +0 -70
- package/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js.flow +0 -150
- package/relay-hooks/react-cache/useRefetchableFragment_REACT_CACHE.js.flow +0 -65
@@ -50,7 +50,12 @@ type FragmentResourceCache = Cache<
|
|
50
50
|
promise: Promise<mixed>,
|
51
51
|
result: FragmentResult,
|
52
52
|
}
|
53
|
-
| {kind: 'done', result: FragmentResult}
|
53
|
+
| {kind: 'done', result: FragmentResult}
|
54
|
+
| {
|
55
|
+
kind: 'missing',
|
56
|
+
result: FragmentResult,
|
57
|
+
snapshot: SingularOrPluralSnapshot,
|
58
|
+
},
|
54
59
|
>;
|
55
60
|
|
56
61
|
const WEAKMAP_SUPPORTED = typeof WeakMap === 'function';
|
@@ -348,16 +353,28 @@ class FragmentResourceImpl {
|
|
348
353
|
componentDisplayName,
|
349
354
|
);
|
350
355
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
356
|
+
let fragmentResult = null;
|
357
|
+
let snapshot = null;
|
358
|
+
// Fall through to existing logic if it's 'missing' state so it would check and save promise into cache.
|
359
|
+
if (
|
360
|
+
RelayFeatureFlags.ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE &&
|
361
|
+
cachedValue != null &&
|
362
|
+
cachedValue.kind === 'missing'
|
363
|
+
) {
|
364
|
+
fragmentResult = cachedValue.result;
|
365
|
+
snapshot = cachedValue.snapshot;
|
366
|
+
} else {
|
367
|
+
snapshot =
|
368
|
+
fragmentSelector.kind === 'PluralReaderSelector'
|
369
|
+
? fragmentSelector.selectors.map(s => environment.lookup(s))
|
370
|
+
: environment.lookup(fragmentSelector);
|
355
371
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
372
|
+
fragmentResult = getFragmentResult(
|
373
|
+
fragmentIdentifier,
|
374
|
+
snapshot,
|
375
|
+
storeEpoch,
|
376
|
+
);
|
377
|
+
}
|
361
378
|
if (!fragmentResult.isMissingData) {
|
362
379
|
this._throwOrLogErrorsInSnapshot(snapshot);
|
363
380
|
|
@@ -483,6 +500,17 @@ class FragmentResourceImpl {
|
|
483
500
|
}
|
484
501
|
}
|
485
502
|
|
503
|
+
// set it as done if has missing data and no pending operations
|
504
|
+
if (
|
505
|
+
RelayFeatureFlags.ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE &&
|
506
|
+
fragmentResult.isMissingData
|
507
|
+
) {
|
508
|
+
this._cache.set(fragmentIdentifier, {
|
509
|
+
kind: 'done',
|
510
|
+
result: fragmentResult,
|
511
|
+
});
|
512
|
+
}
|
513
|
+
|
486
514
|
this._throwOrLogErrorsInSnapshot(snapshot);
|
487
515
|
|
488
516
|
// At this point, there's nothing we can do. We don't have all the expected
|
@@ -617,10 +645,26 @@ class FragmentResourceImpl {
|
|
617
645
|
disposables.push(
|
618
646
|
environment.subscribe(currentSnapshot, latestSnapshot => {
|
619
647
|
const storeEpoch = environment.getStore().getEpoch();
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
648
|
+
const result = getFragmentResult(
|
649
|
+
cacheKey,
|
650
|
+
latestSnapshot,
|
651
|
+
storeEpoch,
|
652
|
+
);
|
653
|
+
if (
|
654
|
+
RelayFeatureFlags.ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE &&
|
655
|
+
result.isMissingData
|
656
|
+
) {
|
657
|
+
this._cache.set(cacheKey, {
|
658
|
+
kind: 'missing',
|
659
|
+
result: result,
|
660
|
+
snapshot: latestSnapshot,
|
661
|
+
});
|
662
|
+
} else {
|
663
|
+
this._cache.set(cacheKey, {
|
664
|
+
kind: 'done',
|
665
|
+
result: getFragmentResult(cacheKey, latestSnapshot, storeEpoch),
|
666
|
+
});
|
667
|
+
}
|
624
668
|
callback();
|
625
669
|
}),
|
626
670
|
);
|
@@ -696,10 +740,26 @@ class FragmentResourceImpl {
|
|
696
740
|
// Only update the cache when the data is changed to avoid
|
697
741
|
// returning different `data` instances
|
698
742
|
if (didMissUpdates) {
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
743
|
+
const result = getFragmentResult(
|
744
|
+
cacheKey,
|
745
|
+
currentSnapshots,
|
746
|
+
storeEpoch,
|
747
|
+
);
|
748
|
+
if (
|
749
|
+
RelayFeatureFlags.ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE &&
|
750
|
+
result.isMissingData
|
751
|
+
) {
|
752
|
+
this._cache.set(cacheKey, {
|
753
|
+
kind: 'missing',
|
754
|
+
result,
|
755
|
+
snapshot: currentSnapshots,
|
756
|
+
});
|
757
|
+
} else {
|
758
|
+
this._cache.set(cacheKey, {
|
759
|
+
kind: 'done',
|
760
|
+
result,
|
761
|
+
});
|
762
|
+
}
|
703
763
|
}
|
704
764
|
return [didMissUpdates, currentSnapshots];
|
705
765
|
}
|
@@ -718,10 +778,26 @@ class FragmentResourceImpl {
|
|
718
778
|
relayResolverErrors: currentSnapshot.relayResolverErrors,
|
719
779
|
};
|
720
780
|
if (updatedData !== renderData) {
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
781
|
+
const result = getFragmentResult(
|
782
|
+
cacheKey,
|
783
|
+
updatedCurrentSnapshot,
|
784
|
+
storeEpoch,
|
785
|
+
);
|
786
|
+
if (
|
787
|
+
RelayFeatureFlags.ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE &&
|
788
|
+
result.isMissingData
|
789
|
+
) {
|
790
|
+
this._cache.set(cacheKey, {
|
791
|
+
kind: 'missing',
|
792
|
+
result: result,
|
793
|
+
snapshot: updatedCurrentSnapshot,
|
794
|
+
});
|
795
|
+
} else {
|
796
|
+
this._cache.set(cacheKey, {
|
797
|
+
kind: 'done',
|
798
|
+
result,
|
799
|
+
});
|
800
|
+
}
|
725
801
|
}
|
726
802
|
return [updatedData !== renderData, updatedCurrentSnapshot];
|
727
803
|
}
|
@@ -799,10 +875,22 @@ class FragmentResourceImpl {
|
|
799
875
|
? [...currentSnapshot]
|
800
876
|
: [...baseSnapshots];
|
801
877
|
nextSnapshots[idx] = latestSnapshot;
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
878
|
+
const result = getFragmentResult(cacheKey, nextSnapshots, storeEpoch);
|
879
|
+
if (
|
880
|
+
RelayFeatureFlags.ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE &&
|
881
|
+
result.isMissingData
|
882
|
+
) {
|
883
|
+
this._cache.set(cacheKey, {
|
884
|
+
kind: 'missing',
|
885
|
+
result,
|
886
|
+
snapshot: nextSnapshots,
|
887
|
+
});
|
888
|
+
} else {
|
889
|
+
this._cache.set(cacheKey, {
|
890
|
+
kind: 'done',
|
891
|
+
result,
|
892
|
+
});
|
893
|
+
}
|
806
894
|
}
|
807
895
|
}
|
808
896
|
|
@@ -11,6 +11,7 @@
|
|
11
11
|
|
12
12
|
'use strict';
|
13
13
|
|
14
|
+
import typeof useFragmentInternal from './experimental/useFragmentInternal_EXPERIMENTAL';
|
14
15
|
import typeof useFragment from './useFragment';
|
15
16
|
import type {UsePaginationFragmentType} from './usePaginationFragment';
|
16
17
|
import type {UseRefetchableFragmentType} from './useRefetchableFragment';
|
@@ -21,13 +22,14 @@ type HooksImplementation = {
|
|
21
22
|
useFragment: useFragment,
|
22
23
|
usePaginationFragment: UsePaginationFragmentType,
|
23
24
|
useRefetchableFragment: UseRefetchableFragmentType,
|
25
|
+
useFragment__internal?: useFragmentInternal,
|
24
26
|
};
|
25
27
|
|
26
28
|
let implementation: HooksImplementation | null = null;
|
27
29
|
|
28
30
|
function inject(impl: HooksImplementation): void {
|
29
31
|
warning(
|
30
|
-
implementation
|
32
|
+
implementation === null,
|
31
33
|
'Relay HooksImplementation was injected twice.',
|
32
34
|
);
|
33
35
|
implementation = impl;
|
@@ -85,8 +85,10 @@ function prepareEntryPoint<
|
|
85
85
|
}
|
86
86
|
const preloadProps = entryPoint.getPreloadProps(entryPointParams);
|
87
87
|
const {queries, entryPoints, extraProps} = preloadProps;
|
88
|
-
|
89
|
-
const
|
88
|
+
// $FlowFixMe[incompatible-type]
|
89
|
+
const preloadedQueries: Partial<TPreloadedQueries> = {};
|
90
|
+
// $FlowFixMe[incompatible-type]
|
91
|
+
const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {};
|
90
92
|
if (queries != null) {
|
91
93
|
const queriesPropNames = Object.keys(queries);
|
92
94
|
queriesPropNames.forEach(queryPropName => {
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
3
|
+
*
|
4
|
+
* This source code is licensed under the MIT license found in the
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
6
|
+
*
|
7
|
+
* @flow strict-local
|
8
|
+
* @format
|
9
|
+
* @oncall relay
|
10
|
+
*/
|
11
|
+
|
12
|
+
'use strict';
|
13
|
+
|
14
|
+
import type {
|
15
|
+
InternalEntryPointRepresentation,
|
16
|
+
ThinNestedEntryPointParams,
|
17
|
+
} from './EntryPointTypes.flow';
|
18
|
+
|
19
|
+
/**
|
20
|
+
* This is an identity function to construct a type safe nested entrypoint.
|
21
|
+
* By calling this function, we ensure that the type of entryPointParams matches
|
22
|
+
* exactly the type of preloadProps of the entrypoint.
|
23
|
+
*
|
24
|
+
* We make the type of `ThinNestedEntryPointParams` opaque, so that the only way
|
25
|
+
* to construct a `ThinNestedEntryPointParams` is by calling this function.
|
26
|
+
*/
|
27
|
+
declare function NestedRelayEntryPoint<
|
28
|
+
TEntryPointParams,
|
29
|
+
TPreloadedQueries,
|
30
|
+
TPreloadedEntryPoints,
|
31
|
+
TRuntimeProps,
|
32
|
+
TExtraProps,
|
33
|
+
>(
|
34
|
+
$ReadOnly<{
|
35
|
+
entryPoint: InternalEntryPointRepresentation<
|
36
|
+
TEntryPointParams,
|
37
|
+
TPreloadedQueries,
|
38
|
+
TPreloadedEntryPoints,
|
39
|
+
TRuntimeProps,
|
40
|
+
TExtraProps,
|
41
|
+
>,
|
42
|
+
entryPointParams: TEntryPointParams,
|
43
|
+
}>,
|
44
|
+
): ThinNestedEntryPointParams;
|
45
|
+
|
46
|
+
// eslint-disable-next-line no-redeclare
|
47
|
+
function NestedRelayEntryPoint<P>(params: P): P {
|
48
|
+
return params;
|
49
|
+
}
|
50
|
+
|
51
|
+
export {NestedRelayEntryPoint};
|
@@ -18,6 +18,8 @@ import type {
|
|
18
18
|
} from '../../EntryPointTypes.flow';
|
19
19
|
import type {JSResourceReference} from 'JSResourceReference';
|
20
20
|
|
21
|
+
import {NestedRelayEntryPoint} from '../../NestedRelayEntryPointBuilderUtils';
|
22
|
+
|
21
23
|
declare function mockJSResource<TModule>(
|
22
24
|
module: TModule,
|
23
25
|
): JSResourceReference<TModule>;
|
@@ -65,14 +67,14 @@ type BadParentEntrypointParams = $ReadOnly<{}>;
|
|
65
67
|
getPreloadProps(_params: BadParentEntrypointParams) {
|
66
68
|
return {
|
67
69
|
entryPoints: {
|
68
|
-
nestedComponent: {
|
69
|
-
entryPoint: NestedEntryPoint,
|
70
|
+
nestedComponent: NestedRelayEntryPoint({
|
70
71
|
/**
|
71
72
|
$FlowExpectedError The entryPointParams here should be of type
|
72
73
|
NestedEntrypointPreloadParams, but it does not contain subEntrypointPreloadParam
|
73
74
|
*/
|
75
|
+
entryPoint: NestedEntryPoint,
|
74
76
|
entryPointParams: Object.freeze({}),
|
75
|
-
},
|
77
|
+
}),
|
76
78
|
},
|
77
79
|
};
|
78
80
|
},
|
@@ -90,13 +92,13 @@ type GoodParentEntrypointParams = $ReadOnly<{}>;
|
|
90
92
|
getPreloadProps(_params: GoodParentEntrypointParams) {
|
91
93
|
return {
|
92
94
|
entryPoints: {
|
93
|
-
nestedComponent: {
|
95
|
+
nestedComponent: NestedRelayEntryPoint({
|
94
96
|
entryPoint: NestedEntryPoint,
|
95
97
|
// No flow error since this matches NestedEntrypointPreloadParams
|
96
98
|
entryPointParams: {
|
97
99
|
subEntrypointPreloadParam: 'test',
|
98
100
|
},
|
99
|
-
},
|
101
|
+
}),
|
100
102
|
},
|
101
103
|
};
|
102
104
|
},
|
@@ -45,6 +45,8 @@ type ExpectedReturnType<
|
|
45
45
|
/* eslint-disable react-hooks/rules-of-hooks */
|
46
46
|
|
47
47
|
// Nullability of returned data type is correct
|
48
|
+
// $FlowFixMe[prop-missing]
|
49
|
+
// $FlowFixMe[incompatible-cast]
|
48
50
|
(useBlockingPaginationFragment(
|
49
51
|
refetchableFragmentInput,
|
50
52
|
keyNonNullable,
|
@@ -112,9 +114,12 @@ const {loadNext} = useBlockingPaginationFragment(
|
|
112
114
|
);
|
113
115
|
// Accepts extraVariables
|
114
116
|
loadNext(10, {
|
117
|
+
// $FlowFixMe[prop-missing]
|
118
|
+
// $FlowFixMe[incompatible-call]
|
115
119
|
UNSTABLE_extraVariables: extraVariables,
|
116
120
|
});
|
117
121
|
|
122
|
+
// $FlowFixMe[prop-missing]
|
118
123
|
loadNext(10, {
|
119
124
|
// $FlowExpectedError: doesn't accept variables not available in the Flow type
|
120
125
|
UNSTABLE_extraVariables: invalidVariables,
|
@@ -47,6 +47,8 @@ type ExpectedReturnType<
|
|
47
47
|
/* eslint-disable react-hooks/rules-of-hooks */
|
48
48
|
|
49
49
|
// Nullability of returned data type is correct
|
50
|
+
// $FlowFixMe[prop-missing]
|
51
|
+
// $FlowFixMe[incompatible-cast]
|
50
52
|
(usePaginationFragment(
|
51
53
|
refetchableFragmentInput,
|
52
54
|
keyNonNullable,
|
@@ -113,9 +115,12 @@ const {loadNext} = usePaginationFragment(
|
|
113
115
|
);
|
114
116
|
// Accepts extraVariables
|
115
117
|
loadNext(10, {
|
118
|
+
// $FlowFixMe[prop-missing]
|
119
|
+
// $FlowFixMe[incompatible-call]
|
116
120
|
UNSTABLE_extraVariables: extraVariables,
|
117
121
|
});
|
118
122
|
|
123
|
+
// $FlowFixMe[prop-missing]
|
119
124
|
loadNext(10, {
|
120
125
|
// $FlowExpectedError: doesn't accept variables not available in the Flow type
|
121
126
|
UNSTABLE_extraVariables: invalidVariables,
|
@@ -31,6 +31,8 @@ import {
|
|
31
31
|
/* eslint-disable react-hooks/rules-of-hooks */
|
32
32
|
|
33
33
|
// Nullability of returned data type is correct
|
34
|
+
// $FlowFixMe[prop-missing]
|
35
|
+
// $FlowFixMe[incompatible-cast]
|
34
36
|
(useRefetchableFragment(refetchableFragmentInput, keyNonNullable): [
|
35
37
|
NonNullableData,
|
36
38
|
FetchFn<QueryVariablesSubset>,
|
@@ -27,6 +27,7 @@ const {getQueryResourceForEnvironment} = require('../QueryResource');
|
|
27
27
|
const invariant = require('invariant');
|
28
28
|
const {
|
29
29
|
__internal: {fetchQuery: fetchQueryInternal},
|
30
|
+
RelayFeatureFlags,
|
30
31
|
createOperationDescriptor,
|
31
32
|
getPendingOperationsForFragment,
|
32
33
|
getSelector,
|
@@ -156,7 +157,7 @@ function getFragmentState(
|
|
156
157
|
}
|
157
158
|
|
158
159
|
// fragmentNode cannot change during the lifetime of the component, though fragmentRef may change.
|
159
|
-
function
|
160
|
+
function readFragmentInternal_EXPERIMENTAL(
|
160
161
|
environment: IEnvironment,
|
161
162
|
fragmentNode: ReaderFragment,
|
162
163
|
fragmentRef: mixed,
|
@@ -268,7 +269,7 @@ function readFragmentInternal_REACT_CACHE(
|
|
268
269
|
data = state.snapshots.map(s => s.data);
|
269
270
|
}
|
270
271
|
|
271
|
-
if (__DEV__) {
|
272
|
+
if (RelayFeatureFlags.LOG_MISSING_RECORDS_IN_PROD || __DEV__) {
|
272
273
|
if (
|
273
274
|
fragmentRef != null &&
|
274
275
|
(data === undefined ||
|
@@ -294,4 +295,4 @@ function readFragmentInternal_REACT_CACHE(
|
|
294
295
|
return {data, clientEdgeQueries};
|
295
296
|
}
|
296
297
|
|
297
|
-
module.exports =
|
298
|
+
module.exports = readFragmentInternal_EXPERIMENTAL;
|
@@ -32,6 +32,7 @@ const invariant = require('invariant');
|
|
32
32
|
const {useDebugValue, useEffect, useMemo, useRef, useState} = require('react');
|
33
33
|
const {
|
34
34
|
__internal: {fetchQuery: fetchQueryInternal},
|
35
|
+
RelayFeatureFlags,
|
35
36
|
areEqualSelectors,
|
36
37
|
createOperationDescriptor,
|
37
38
|
getPendingOperationsForFragment,
|
@@ -256,7 +257,17 @@ function subscribeToSnapshot(
|
|
256
257
|
prevState.kind !== 'singular' ||
|
257
258
|
prevState.snapshot.selector !== latestSnapshot.selector
|
258
259
|
) {
|
259
|
-
|
260
|
+
const updates = handleMissedUpdates(environment, prevState);
|
261
|
+
if (updates != null) {
|
262
|
+
const [dataChanged, nextState] = updates;
|
263
|
+
environment.__log({
|
264
|
+
name: 'useFragment.subscription.missedUpdates',
|
265
|
+
hasDataChanges: dataChanged,
|
266
|
+
});
|
267
|
+
return dataChanged ? nextState : prevState;
|
268
|
+
} else {
|
269
|
+
return prevState;
|
270
|
+
}
|
260
271
|
}
|
261
272
|
return {
|
262
273
|
kind: 'singular',
|
@@ -279,7 +290,17 @@ function subscribeToSnapshot(
|
|
279
290
|
prevState.kind !== 'plural' ||
|
280
291
|
prevState.snapshots[index]?.selector !== latestSnapshot.selector
|
281
292
|
) {
|
282
|
-
|
293
|
+
const updates = handleMissedUpdates(environment, prevState);
|
294
|
+
if (updates != null) {
|
295
|
+
const [dataChanged, nextState] = updates;
|
296
|
+
environment.__log({
|
297
|
+
name: 'useFragment.subscription.missedUpdates',
|
298
|
+
hasDataChanges: dataChanged,
|
299
|
+
});
|
300
|
+
return dataChanged ? nextState : prevState;
|
301
|
+
} else {
|
302
|
+
return prevState;
|
303
|
+
}
|
283
304
|
}
|
284
305
|
const updated = [...prevState.snapshots];
|
285
306
|
updated[index] = latestSnapshot;
|
@@ -323,12 +344,11 @@ function getFragmentState(
|
|
323
344
|
}
|
324
345
|
|
325
346
|
// fragmentNode cannot change during the lifetime of the component, though fragmentRef may change.
|
326
|
-
function
|
347
|
+
function useFragmentInternal_EXPERIMENTAL(
|
327
348
|
fragmentNode: ReaderFragment,
|
328
349
|
fragmentRef: mixed,
|
329
350
|
hookDisplayName: string,
|
330
351
|
queryOptions?: FragmentQueryOptions,
|
331
|
-
fragmentKey?: string,
|
332
352
|
): ?SelectorData | Array<?SelectorData> {
|
333
353
|
const fragmentSelector = useMemo(
|
334
354
|
() => getSelector(fragmentNode, fragmentRef),
|
@@ -343,7 +363,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
343
363
|
'Relay: Expected fragment pointer%s for fragment `%s` to be ' +
|
344
364
|
'an array, instead got `%s`. Remove `@relay(plural: true)` ' +
|
345
365
|
'from fragment `%s` to allow the prop to be an object.',
|
346
|
-
fragmentKey != null ? ` for key \`${fragmentKey}\`` : '',
|
347
366
|
fragmentNode.name,
|
348
367
|
typeof fragmentRef,
|
349
368
|
fragmentNode.name,
|
@@ -354,7 +373,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
354
373
|
'Relay: Expected fragment pointer%s for fragment `%s` not to be ' +
|
355
374
|
'an array, instead got `%s`. Add `@relay(plural: true)` ' +
|
356
375
|
'to fragment `%s` to allow the prop to be an array.',
|
357
|
-
fragmentKey != null ? ` for key \`${fragmentKey}\`` : '',
|
358
376
|
fragmentNode.name,
|
359
377
|
typeof fragmentRef,
|
360
378
|
fragmentNode.name,
|
@@ -378,7 +396,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
378
396
|
fragmentNode.name,
|
379
397
|
hookDisplayName,
|
380
398
|
fragmentNode.name,
|
381
|
-
fragmentKey == null ? 'a fragment reference' : `the \`${fragmentKey}\``,
|
382
399
|
hookDisplayName,
|
383
400
|
);
|
384
401
|
|
@@ -418,7 +435,7 @@ function useFragmentInternal_REACT_CACHE(
|
|
418
435
|
// The purpose of this is to detect whether we have ever committed, because we
|
419
436
|
// don't suspend on store updates, only when the component either is first trying
|
420
437
|
// to mount or when the our selector changes. The selector change in particular is
|
421
|
-
// how we suspend for pagination and
|
438
|
+
// how we suspend for pagination and refetch. Also, fragment selector can be null
|
422
439
|
// or undefined, so we use false as a special value to distinguish from all fragment
|
423
440
|
// selectors; false means that the component hasn't mounted yet.
|
424
441
|
const committedFragmentSelectorRef = useRef<false | ?ReaderSelector>(false);
|
@@ -505,11 +522,12 @@ function useFragmentInternal_REACT_CACHE(
|
|
505
522
|
throw pendingOperationsResult.promise;
|
506
523
|
}
|
507
524
|
}
|
508
|
-
// Report required fields only if we're not suspending, since that means
|
509
|
-
// they're missing even though we are out of options for possibly fetching them:
|
510
|
-
handlePotentialSnapshotErrorsForState(environment, state);
|
511
525
|
}
|
512
526
|
|
527
|
+
// Report required fields only if we're not suspending, since that means
|
528
|
+
// they're missing even though we are out of options for possibly fetching them:
|
529
|
+
handlePotentialSnapshotErrorsForState(environment, state);
|
530
|
+
|
513
531
|
useEffect(() => {
|
514
532
|
// Check for updates since the state was rendered
|
515
533
|
let currentState = subscribedState;
|
@@ -533,7 +551,7 @@ function useFragmentInternal_REACT_CACHE(
|
|
533
551
|
|
534
552
|
let data: ?SelectorData | Array<?SelectorData>;
|
535
553
|
if (isPlural) {
|
536
|
-
// Plural fragments require allocating an array of the
|
554
|
+
// Plural fragments require allocating an array of the snapshot data values,
|
537
555
|
// which has to be memoized to avoid triggering downstream re-renders.
|
538
556
|
//
|
539
557
|
// Note that isPlural is a constant property of the fragment and does not change
|
@@ -565,7 +583,7 @@ function useFragmentInternal_REACT_CACHE(
|
|
565
583
|
data = state.snapshot.data;
|
566
584
|
}
|
567
585
|
|
568
|
-
if (__DEV__) {
|
586
|
+
if (RelayFeatureFlags.LOG_MISSING_RECORDS_IN_PROD || __DEV__) {
|
569
587
|
if (
|
570
588
|
fragmentRef != null &&
|
571
589
|
(data === undefined ||
|
@@ -596,4 +614,4 @@ function useFragmentInternal_REACT_CACHE(
|
|
596
614
|
return data;
|
597
615
|
}
|
598
616
|
|
599
|
-
module.exports =
|
617
|
+
module.exports = useFragmentInternal_EXPERIMENTAL;
|
@@ -15,7 +15,7 @@ import type {Fragment, FragmentType, GraphQLTaggedNode} from 'relay-runtime';
|
|
15
15
|
|
16
16
|
const {useTrackLoadQueryInRender} = require('../loadQuery');
|
17
17
|
const useStaticFragmentNodeWarning = require('../useStaticFragmentNodeWarning');
|
18
|
-
const useFragmentInternal = require('./
|
18
|
+
const useFragmentInternal = require('./useFragmentInternal_EXPERIMENTAL');
|
19
19
|
const {useDebugValue} = require('react');
|
20
20
|
const {getFragment} = require('relay-runtime');
|
21
21
|
|
@@ -30,23 +30,17 @@ declare function useFragment<TFragmentType: FragmentType, TData>(
|
|
30
30
|
key: HasSpread<TFragmentType>,
|
31
31
|
): TData;
|
32
32
|
|
33
|
-
// if the key is nullable, return nullable value
|
34
|
-
declare function useFragment<TFragmentType: FragmentType, TData>(
|
35
|
-
fragment: Fragment<TFragmentType, TData>,
|
36
|
-
key: ?HasSpread<TFragmentType>,
|
37
|
-
): ?TData;
|
38
|
-
|
39
33
|
// if the key is a non-nullable array of keys, return non-nullable array
|
40
34
|
declare function useFragment<TFragmentType: FragmentType, TData>(
|
41
35
|
fragment: Fragment<TFragmentType, TData>,
|
42
36
|
key: $ReadOnlyArray<HasSpread<TFragmentType>>,
|
43
37
|
): TData;
|
44
38
|
|
45
|
-
// if the key is
|
39
|
+
// if the key is null/void, return null/void value
|
46
40
|
declare function useFragment<TFragmentType: FragmentType, TData>(
|
47
41
|
fragment: Fragment<TFragmentType, TData>,
|
48
|
-
key:
|
49
|
-
):
|
42
|
+
key: null | void,
|
43
|
+
): null | void;
|
50
44
|
|
51
45
|
function useFragment(fragment: GraphQLTaggedNode, key: mixed): mixed {
|
52
46
|
// We need to use this hook in order to be able to track if
|