react-relay 0.0.0-main-99abbcde → 0.0.0-main-56cda151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReactRelayContext.js +1 -1
- package/hooks.js +1 -1
- package/index.js +1 -1
- package/legacy.js +1 -1
- package/lib/relay-hooks/rsc/useQueryFromServer.js +28 -20
- package/package.json +2 -2
- package/relay-hooks/rsc/useQueryFromServer.js.flow +64 -37
- package/rsc-client_EXPERIMENTAL.js +1 -1
- package/rsc_EXPERIMENTAL.js +1 -1
package/ReactRelayContext.js
CHANGED
package/hooks.js
CHANGED
package/index.js
CHANGED
package/legacy.js
CHANGED
|
@@ -3,49 +3,57 @@
|
|
|
3
3
|
|
|
4
4
|
var usePreloadedQuery = require('../usePreloadedQuery');
|
|
5
5
|
var useRelayEnvironment = require('../useRelayEnvironment');
|
|
6
|
+
var invariant = require('invariant');
|
|
6
7
|
var _require = require('react'),
|
|
7
8
|
use = _require.use,
|
|
9
|
+
useEffect = _require.useEffect,
|
|
10
|
+
useLayoutEffect = _require.useLayoutEffect,
|
|
8
11
|
useMemo = _require.useMemo;
|
|
9
12
|
var _require2 = require('relay-runtime'),
|
|
10
|
-
|
|
11
|
-
ROOT_TYPE = _require2.ROOT_TYPE,
|
|
13
|
+
RelayModernEnvironment = _require2.Environment,
|
|
12
14
|
createOperationDescriptor = _require2.createOperationDescriptor,
|
|
13
15
|
getRequest = _require2.getRequest;
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
var
|
|
16
|
+
var publishedQueryRefs = new WeakMap();
|
|
17
|
+
function getPublishedQueryRefs(environment) {
|
|
18
|
+
var refs = publishedQueryRefs.get(environment);
|
|
19
|
+
if (refs == null) {
|
|
20
|
+
refs = new WeakMap();
|
|
21
|
+
publishedQueryRefs.set(environment, refs);
|
|
22
|
+
}
|
|
23
|
+
return refs;
|
|
24
|
+
}
|
|
17
25
|
var DEFAULT_STALE_MS = 30_000;
|
|
26
|
+
var useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
|
|
18
27
|
function useQueryFromServer(query, queryRef, options) {
|
|
19
|
-
var _options$staleThresho, _environment$
|
|
28
|
+
var _options$staleThresho, _environment$construc, _environment$construc2;
|
|
20
29
|
var environment = useRelayEnvironment();
|
|
21
30
|
var request = getRequest(query);
|
|
22
31
|
var threshold = (_options$staleThresho = options === null || options === void 0 ? void 0 : options.staleThresholdMs) !== null && _options$staleThresho !== void 0 ? _options$staleThresho : DEFAULT_STALE_MS;
|
|
23
|
-
var getDataID = (_environment$_getData = environment._getDataID) !== null && _environment$_getData !== void 0 ? _environment$_getData : defaultGetDataID;
|
|
24
32
|
var response = use(queryRef._response);
|
|
25
33
|
var isFresh = response.data != null && Date.now() - queryRef.fetchedAt <= threshold;
|
|
26
|
-
|
|
34
|
+
!(environment instanceof RelayModernEnvironment) ? process.env.NODE_ENV !== "production" ? invariant(false, 'useQueryFromServer: expected a RelayModernEnvironment, got `%s`. ' + 'useQueryFromServer is currently only compatible with RelayModernStore.', (_environment$construc = (_environment$construc2 = environment.constructor) === null || _environment$construc2 === void 0 ? void 0 : _environment$construc2.name) !== null && _environment$construc !== void 0 ? _environment$construc : typeof environment) : invariant(false) : void 0;
|
|
35
|
+
var publishedRefs = getPublishedQueryRefs(environment);
|
|
36
|
+
var shouldCommit = isFresh && !publishedRefs.has(queryRef);
|
|
27
37
|
if (shouldCommit) {
|
|
28
|
-
var _environment$__log;
|
|
29
|
-
committedRefs.add(queryRef);
|
|
30
38
|
var operation = createOperationDescriptor(request, queryRef.variables);
|
|
31
39
|
var responsePayload = {
|
|
32
40
|
data: response.data,
|
|
33
41
|
errors: response.errors
|
|
34
42
|
};
|
|
35
|
-
|
|
36
|
-
getDataID: getDataID,
|
|
37
|
-
treatMissingFieldsAsNull: false,
|
|
38
|
-
deferDeduplicatedFields: false,
|
|
39
|
-
log: (_environment$__log = environment.__log) !== null && _environment$__log !== void 0 ? _environment$__log : null,
|
|
40
|
-
path: [],
|
|
41
|
-
shouldProcessClientComponents: false
|
|
42
|
-
}, false);
|
|
43
|
-
environment.getStore().publish(relayPayload.source);
|
|
43
|
+
publishedRefs.set(queryRef, environment.publishWithDeferredNotify(operation, responsePayload));
|
|
44
44
|
}
|
|
45
|
+
useIsomorphicLayoutEffect(function () {
|
|
46
|
+
var refs = getPublishedQueryRefs(environment);
|
|
47
|
+
var flushNotify = refs.get(queryRef);
|
|
48
|
+
if (flushNotify != null) {
|
|
49
|
+
refs.set(queryRef, null);
|
|
50
|
+
flushNotify();
|
|
51
|
+
}
|
|
52
|
+
}, [environment, queryRef]);
|
|
45
53
|
var preloadedQuery = useMemo(function () {
|
|
46
54
|
var _request$params$id;
|
|
47
55
|
var isFreshAtMemo = response.data != null && Date.now() - queryRef.fetchedAt <= threshold;
|
|
48
|
-
var useStore = isFreshAtMemo ||
|
|
56
|
+
var useStore = isFreshAtMemo || getPublishedQueryRefs(environment).has(queryRef);
|
|
49
57
|
return {
|
|
50
58
|
kind: 'PreloadedQuery_DEPRECATED',
|
|
51
59
|
environment: environment,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-relay",
|
|
3
3
|
"description": "A framework for building GraphQL-driven React applications.",
|
|
4
|
-
"version": "0.0.0-main-
|
|
4
|
+
"version": "0.0.0-main-56cda151",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphql",
|
|
7
7
|
"relay",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"fbjs": "^3.0.2",
|
|
21
21
|
"invariant": "^2.2.4",
|
|
22
22
|
"nullthrows": "^1.1.1",
|
|
23
|
-
"relay-runtime": "0.0.0-main-
|
|
23
|
+
"relay-runtime": "0.0.0-main-56cda151"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"react": "^16.9.0 || ^17 || ^18 || ^19"
|
|
@@ -16,26 +16,50 @@ import type {
|
|
|
16
16
|
PreloadedQueryRef,
|
|
17
17
|
PreloadedQueryResponse,
|
|
18
18
|
} from './serverPreloadQuery';
|
|
19
|
-
import type {Query, Variables} from 'relay-runtime';
|
|
19
|
+
import type {IEnvironment, Query, Variables} from 'relay-runtime';
|
|
20
20
|
|
|
21
21
|
const usePreloadedQuery = require('../usePreloadedQuery');
|
|
22
22
|
const useRelayEnvironment = require('../useRelayEnvironment');
|
|
23
|
+
const invariant = require('invariant');
|
|
23
24
|
// $FlowFixMe[missing-export] React.use is available in React 19+
|
|
24
|
-
const {use, useMemo} = require('react');
|
|
25
|
+
const {use, useEffect, useLayoutEffect, useMemo} = require('react');
|
|
25
26
|
const {
|
|
26
|
-
|
|
27
|
-
ROOT_TYPE,
|
|
27
|
+
Environment: RelayModernEnvironment,
|
|
28
28
|
createOperationDescriptor,
|
|
29
29
|
getRequest,
|
|
30
30
|
} = require('relay-runtime');
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
|
|
32
|
+
// Which refs have been published to which environment, and the notify each
|
|
33
|
+
// still owes. Module state, not a component ref: the attempt that publishes
|
|
34
|
+
// need not be the attempt that commits. Keyed by environment because
|
|
35
|
+
// "published" is a fact about one store.
|
|
36
|
+
const publishedQueryRefs: WeakMap<
|
|
37
|
+
IEnvironment,
|
|
38
|
+
// $FlowFixMe[unclear-type] keyed by ref identity only
|
|
39
|
+
WeakMap<any, (() => void) | null>,
|
|
40
|
+
> = new WeakMap();
|
|
41
|
+
|
|
42
|
+
function getPublishedQueryRefs(
|
|
43
|
+
environment: IEnvironment,
|
|
44
|
+
// $FlowFixMe[unclear-type] keyed by ref identity only
|
|
45
|
+
): WeakMap<any, (() => void) | null> {
|
|
46
|
+
let refs = publishedQueryRefs.get(environment);
|
|
47
|
+
if (refs == null) {
|
|
48
|
+
refs = new WeakMap();
|
|
49
|
+
publishedQueryRefs.set(environment, refs);
|
|
50
|
+
}
|
|
51
|
+
return refs;
|
|
52
|
+
}
|
|
36
53
|
|
|
37
54
|
const DEFAULT_STALE_MS = 30_000;
|
|
38
55
|
|
|
56
|
+
// This is a 'use client' hook, so it still renders during SSR, where
|
|
57
|
+
// useLayoutEffect warns and does nothing. There is no notify to flush there
|
|
58
|
+
// either: nothing is subscribed to a server render's store.
|
|
59
|
+
const useIsomorphicLayoutEffect =
|
|
60
|
+
// $FlowFixMe[cannot-resolve-name] `window` has no libdef in the OSS build
|
|
61
|
+
typeof window === 'undefined' ? useEffect : useLayoutEffect;
|
|
62
|
+
|
|
39
63
|
hook useQueryFromServer<TVariables extends Variables, TData>(
|
|
40
64
|
query: Query<TVariables, TData>,
|
|
41
65
|
queryRef: PreloadedQueryRef<TVariables, TData>,
|
|
@@ -44,26 +68,25 @@ hook useQueryFromServer<TVariables extends Variables, TData>(
|
|
|
44
68
|
const environment = useRelayEnvironment();
|
|
45
69
|
const request = getRequest(query);
|
|
46
70
|
const threshold = options?.staleThresholdMs ?? DEFAULT_STALE_MS;
|
|
47
|
-
// TODO: Add a method to IEnvironment for server-side publish so custom
|
|
48
|
-
// IEnvironment implementations don't need to access _getDataID.
|
|
49
|
-
// $FlowFixMe[prop-missing] _getDataID is not on IEnvironment
|
|
50
|
-
// $FlowFixMe[unclear-type]
|
|
51
|
-
const getDataID: any = environment._getDataID ?? defaultGetDataID;
|
|
52
71
|
|
|
53
72
|
const response: PreloadedQueryResponse<TData> = use(queryRef._response);
|
|
54
73
|
|
|
55
74
|
const isFresh =
|
|
56
75
|
response.data != null && Date.now() - queryRef.fetchedAt <= threshold;
|
|
57
76
|
|
|
58
|
-
|
|
77
|
+
// `publishWithDeferredNotify` is on RelayModernEnvironment rather than
|
|
78
|
+
// IEnvironment while the API is experimental.
|
|
79
|
+
invariant(
|
|
80
|
+
environment instanceof RelayModernEnvironment,
|
|
81
|
+
'useQueryFromServer: expected a RelayModernEnvironment, got `%s`. ' +
|
|
82
|
+
'useQueryFromServer is currently only compatible with RelayModernStore.',
|
|
83
|
+
environment.constructor?.name ?? typeof environment,
|
|
84
|
+
);
|
|
59
85
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// different component" error that occurs when store.notify() triggers
|
|
63
|
-
// setState in other mounted components that subscribe to overlapping records.
|
|
64
|
-
if (shouldCommit) {
|
|
65
|
-
committedRefs.add(queryRef);
|
|
86
|
+
const publishedRefs = getPublishedQueryRefs(environment);
|
|
87
|
+
const shouldCommit = isFresh && !publishedRefs.has(queryRef);
|
|
66
88
|
|
|
89
|
+
if (shouldCommit) {
|
|
67
90
|
const operation = createOperationDescriptor(request, queryRef.variables);
|
|
68
91
|
|
|
69
92
|
// $FlowFixMe[unclear-type]
|
|
@@ -71,25 +94,28 @@ hook useQueryFromServer<TVariables extends Variables, TData>(
|
|
|
71
94
|
data: response.data,
|
|
72
95
|
errors: response.errors,
|
|
73
96
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
operation
|
|
77
|
-
ROOT_TYPE,
|
|
78
|
-
{
|
|
79
|
-
getDataID,
|
|
80
|
-
treatMissingFieldsAsNull: false,
|
|
81
|
-
deferDeduplicatedFields: false,
|
|
82
|
-
// $FlowFixMe[prop-missing]
|
|
83
|
-
log: environment.__log ?? null,
|
|
84
|
-
path: [],
|
|
85
|
-
shouldProcessClientComponents: false,
|
|
86
|
-
},
|
|
87
|
-
false,
|
|
97
|
+
publishedRefs.set(
|
|
98
|
+
queryRef,
|
|
99
|
+
environment.publishWithDeferredNotify(operation, responsePayload),
|
|
88
100
|
);
|
|
89
|
-
|
|
90
|
-
environment.getStore().publish(relayPayload.source);
|
|
91
101
|
}
|
|
92
102
|
|
|
103
|
+
// A layout effect rather than during render, which would be a setState in
|
|
104
|
+
// another component mid-render, and rather than a microtask, which can land
|
|
105
|
+
// between concurrent-render work units. Not airtight: a subtree that renders
|
|
106
|
+
// but never mounts never runs this, and its notify waits for the next one.
|
|
107
|
+
useIsomorphicLayoutEffect(() => {
|
|
108
|
+
const refs = getPublishedQueryRefs(environment);
|
|
109
|
+
const flushNotify = refs.get(queryRef);
|
|
110
|
+
if (flushNotify != null) {
|
|
111
|
+
// Null rather than delete: the entry is also what marks this ref
|
|
112
|
+
// published, so removing it would republish on the next render and flip
|
|
113
|
+
// the fetch policy below back to network-only.
|
|
114
|
+
refs.set(queryRef, null);
|
|
115
|
+
flushNotify();
|
|
116
|
+
}
|
|
117
|
+
}, [environment, queryRef]);
|
|
118
|
+
|
|
93
119
|
// Build a PreloadedQuery shim. Fresh data was committed to the store
|
|
94
120
|
// above, so source is null and fetchPolicy is "store-or-network".
|
|
95
121
|
// Stale path uses "network-only" to trigger a client-side refetch.
|
|
@@ -101,7 +127,8 @@ hook useQueryFromServer<TVariables extends Variables, TData>(
|
|
|
101
127
|
// component instance, read from the store even if the server timestamp
|
|
102
128
|
// is past the staleness threshold. This prevents a network refetch
|
|
103
129
|
// from overwriting store mutations made after the initial commit.
|
|
104
|
-
const useStore =
|
|
130
|
+
const useStore =
|
|
131
|
+
isFreshAtMemo || getPublishedQueryRefs(environment).has(queryRef);
|
|
105
132
|
|
|
106
133
|
return {
|
|
107
134
|
kind: 'PreloadedQuery_DEPRECATED',
|
package/rsc_EXPERIMENTAL.js
CHANGED