relay-runtime 20.1.0 → 21.0.0
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/experimental.js +1 -1
- package/experimental.js.flow +8 -8
- package/handlers/connection/ConnectionHandler.js.flow +5 -5
- package/handlers/connection/ConnectionInterface.js.flow +1 -1
- package/index.js +1 -1
- package/index.js.flow +125 -62
- package/lib/experimental.js +3 -3
- package/lib/index.js +105 -57
- package/lib/multi-actor-environment/ActorIdentifier.js +2 -2
- package/lib/multi-actor-environment/MultiActorEnvironment.js +3 -1
- package/lib/mutations/commitMutation.js +8 -8
- package/lib/mutations/validateMutation.js +4 -4
- package/lib/query/GraphQLTag.js +3 -3
- package/lib/query/fetchQuery.js +15 -3
- package/lib/store/DataChecker.js +38 -4
- package/lib/store/NormalizationEngine.js +373 -0
- package/lib/store/OperationExecutor.js +172 -113
- package/lib/store/RelayConcreteVariables.js +1 -1
- package/lib/store/RelayErrorTrie.js +2 -2
- package/lib/store/RelayExperimentalGraphResponseTransform.js +8 -8
- package/lib/store/RelayModernEnvironment.js +26 -19
- package/lib/store/RelayModernRecord.js +18 -8
- package/lib/store/RelayModernSelector.js +9 -9
- package/lib/store/RelayModernStore.js +152 -43
- package/lib/store/RelayPublishQueue.js +1 -1
- package/lib/store/RelayReader.js +76 -38
- package/lib/store/RelayRecordSource.js +6 -0
- package/lib/store/RelayReferenceMarker.js +2 -1
- package/lib/store/RelayResponseNormalizer.js +88 -55
- package/lib/store/RelayStoreSubscriptions.js +34 -10
- package/lib/store/RelayStoreUtils.js +8 -1
- package/lib/store/ResolverFragments.js +2 -2
- package/lib/store/live-resolvers/LiveResolverCache.js +25 -9
- package/lib/store/observeFragmentExperimental.js +17 -1
- package/lib/store/observeQueryExperimental.js +2 -2
- package/lib/subscription/requestSubscription.js +3 -3
- package/lib/util/RelayError.js +3 -0
- package/lib/util/RelayFeatureFlags.js +6 -2
- package/lib/util/RelayReplaySubject.js +4 -4
- package/lib/util/handlePotentialSnapshotErrors.js +2 -2
- package/lib/util/stableCopy.js +2 -2
- package/llm-docs/api-reference/entrypoint-apis/entrypoint-container.mdx +38 -0
- package/llm-docs/api-reference/entrypoint-apis/load-entrypoint.mdx +77 -0
- package/llm-docs/api-reference/entrypoint-apis/use-entrypoint-loader.mdx +99 -0
- package/llm-docs/api-reference/graphql/graphql-directives.mdx +378 -0
- package/llm-docs/api-reference/hooks/_use-lazy-load-query-extra.mdx +16 -0
- package/llm-docs/api-reference/hooks/load-query.mdx +84 -0
- package/llm-docs/api-reference/hooks/relay-environment-provider.mdx +78 -0
- package/llm-docs/api-reference/hooks/use-client-query.mdx +65 -0
- package/llm-docs/api-reference/hooks/use-fragment.mdx +69 -0
- package/llm-docs/api-reference/hooks/use-lazy-load-query.mdx +62 -0
- package/llm-docs/api-reference/hooks/use-mutation.mdx +94 -0
- package/llm-docs/api-reference/hooks/use-pagination-fragment.mdx +166 -0
- package/llm-docs/api-reference/hooks/use-prefetchable-forward-pagination-fragment.mdx +134 -0
- package/llm-docs/api-reference/hooks/use-preloaded-query.mdx +84 -0
- package/llm-docs/api-reference/hooks/use-query-loader.mdx +95 -0
- package/llm-docs/api-reference/hooks/use-refetchable-fragment.mdx +122 -0
- package/llm-docs/api-reference/hooks/use-relay-environment.mdx +37 -0
- package/llm-docs/api-reference/hooks/use-subscription.mdx +66 -0
- package/llm-docs/api-reference/relay-resolvers/docblock-format.mdx +321 -0
- package/llm-docs/api-reference/relay-resolvers/runtime-functions.mdx +94 -0
- package/llm-docs/api-reference/relay-runtime/commit-mutation.mdx +65 -0
- package/llm-docs/api-reference/relay-runtime/fetch-query.mdx +113 -0
- package/llm-docs/api-reference/relay-runtime/field-logger.mdx +170 -0
- package/llm-docs/api-reference/relay-runtime/observe-fragment.mdx +92 -0
- package/llm-docs/api-reference/relay-runtime/relay-environment.mdx +53 -0
- package/llm-docs/api-reference/relay-runtime/request-subscription.mdx +54 -0
- package/llm-docs/api-reference/relay-runtime/runtime-configuration.mdx +52 -0
- package/llm-docs/api-reference/relay-runtime/store.mdx +734 -0
- package/llm-docs/api-reference/relay-runtime/wait-for-fragment-data.mdx +89 -0
- package/llm-docs/api-reference/types/CacheConfig.mdx +8 -0
- package/llm-docs/api-reference/types/Disposable.mdx +4 -0
- package/llm-docs/api-reference/types/GraphQLSubscriptionConfig.mdx +17 -0
- package/llm-docs/api-reference/types/MutationConfig.mdx +31 -0
- package/llm-docs/api-reference/types/SelectorStoreUpdater.mdx +6 -0
- package/llm-docs/api-reference/types/UploadableMap.mdx +3 -0
- package/llm-docs/community/learning-resources.mdx +64 -0
- package/llm-docs/debugging/declarative-mutation-directives.mdx +34 -0
- package/llm-docs/debugging/disallowed-id-types-error.mdx +43 -0
- package/llm-docs/debugging/inconsistent-typename-error.mdx +47 -0
- package/llm-docs/debugging/relay-devtools.mdx +73 -0
- package/llm-docs/debugging/why-null.mdx +116 -0
- package/llm-docs/editor-support.mdx +55 -0
- package/llm-docs/error-reference/unknown-field.mdx +36 -0
- package/llm-docs/getting-started/babel-plugin.mdx +31 -0
- package/llm-docs/getting-started/compiler-config.mdx +25 -0
- package/llm-docs/getting-started/compiler.mdx +82 -0
- package/llm-docs/getting-started/lint-rules.mdx +87 -0
- package/llm-docs/getting-started/production.mdx +30 -0
- package/llm-docs/getting-started/quick-start.mdx +213 -0
- package/llm-docs/glossary/glossary.mdx +1040 -0
- package/llm-docs/guided-tour/list-data/advanced-pagination.mdx +157 -0
- package/llm-docs/guided-tour/list-data/connections.mdx +81 -0
- package/llm-docs/guided-tour/list-data/pagination.mdx +193 -0
- package/llm-docs/guided-tour/list-data/rendering-connections.mdx +112 -0
- package/llm-docs/guided-tour/list-data/streaming-pagination.mdx +87 -0
- package/llm-docs/guided-tour/managing-data-outside-react/retaining-queries.mdx +51 -0
- package/llm-docs/guided-tour/refetching/refetching-queries-with-different-data.mdx +337 -0
- package/llm-docs/guided-tour/refetching/refreshing-queries.mdx +350 -0
- package/llm-docs/guided-tour/rendering/environment.mdx +59 -0
- package/llm-docs/guided-tour/rendering/error-states.mdx +295 -0
- package/llm-docs/guided-tour/rendering/fragments.mdx +354 -0
- package/llm-docs/guided-tour/rendering/loading-states.mdx +245 -0
- package/llm-docs/guided-tour/rendering/queries.mdx +261 -0
- package/llm-docs/guided-tour/rendering/variables.mdx +233 -0
- package/llm-docs/guided-tour/reusing-cached-data/fetch-policies.mdx +56 -0
- package/llm-docs/guided-tour/reusing-cached-data/filling-in-missing-data.mdx +102 -0
- package/llm-docs/guided-tour/reusing-cached-data/introduction.mdx +22 -0
- package/llm-docs/guided-tour/reusing-cached-data/presence-of-data.mdx +93 -0
- package/llm-docs/guided-tour/reusing-cached-data/rendering-partially-cached-data.mdx +175 -0
- package/llm-docs/guided-tour/reusing-cached-data/staleness-of-data.mdx +116 -0
- package/llm-docs/guided-tour/updating-data/client-only-data.mdx +115 -0
- package/llm-docs/guided-tour/updating-data/graphql-mutations.mdx +334 -0
- package/llm-docs/guided-tour/updating-data/graphql-subscriptions.mdx +279 -0
- package/llm-docs/guided-tour/updating-data/imperatively-modifying-linked-fields.mdx +511 -0
- package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data-legacy.mdx +142 -0
- package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data.mdx +275 -0
- package/llm-docs/guided-tour/updating-data/introduction.mdx +25 -0
- package/llm-docs/guided-tour/updating-data/local-data-updates.mdx +71 -0
- package/llm-docs/guided-tour/updating-data/typesafe-updaters-faq.mdx +83 -0
- package/llm-docs/guided-tour/updating-data/updating-connections.mdx +592 -0
- package/llm-docs/guides/alias-directive.mdx +160 -0
- package/llm-docs/guides/catch-directive.mdx +167 -0
- package/llm-docs/guides/client-schema-extensions.mdx +208 -0
- package/llm-docs/guides/codemods.mdx +66 -0
- package/llm-docs/guides/data-driven-dependencies/client-3d.mdx +255 -0
- package/llm-docs/guides/data-driven-dependencies/configuration.mdx +127 -0
- package/llm-docs/guides/data-driven-dependencies/introduction.mdx +39 -0
- package/llm-docs/guides/data-driven-dependencies/server-3d.mdx +664 -0
- package/llm-docs/guides/document-comparison.mdx +106 -0
- package/llm-docs/guides/graphql-server-specification.mdx +453 -0
- package/llm-docs/guides/network-layer.mdx +69 -0
- package/llm-docs/guides/persisted-queries.mdx +328 -0
- package/llm-docs/guides/relay-resolvers/context.mdx +99 -0
- package/llm-docs/guides/relay-resolvers/defining-fields.mdx +151 -0
- package/llm-docs/guides/relay-resolvers/defining-types.mdx +164 -0
- package/llm-docs/guides/relay-resolvers/deprecated.mdx +27 -0
- package/llm-docs/guides/relay-resolvers/derived-fields.mdx +127 -0
- package/llm-docs/guides/relay-resolvers/descriptions.mdx +44 -0
- package/llm-docs/guides/relay-resolvers/enabling.mdx +41 -0
- package/llm-docs/guides/relay-resolvers/errors.mdx +64 -0
- package/llm-docs/guides/relay-resolvers/field-arguments.mdx +63 -0
- package/llm-docs/guides/relay-resolvers/introduction.mdx +62 -0
- package/llm-docs/guides/relay-resolvers/limitations.mdx +30 -0
- package/llm-docs/guides/relay-resolvers/live-fields.mdx +164 -0
- package/llm-docs/guides/relay-resolvers/return-types.mdx +161 -0
- package/llm-docs/guides/relay-resolvers/suspense.mdx +41 -0
- package/llm-docs/guides/required-directive.mdx +240 -0
- package/llm-docs/guides/semantic-nullability.mdx +93 -0
- package/llm-docs/guides/testing-relay-components.mdx +642 -0
- package/llm-docs/guides/testing-relay-with-preloaded-queries.mdx +160 -0
- package/llm-docs/guides/throw-on-field-error-directive.mdx +58 -0
- package/llm-docs/guides/type-emission.mdx +414 -0
- package/llm-docs/home.mdx +32 -0
- package/llm-docs/principles-and-architecture/architecture-overview.mdx +24 -0
- package/llm-docs/principles-and-architecture/compiler-architecture.mdx +106 -0
- package/llm-docs/principles-and-architecture/runtime-architecture.mdx +249 -0
- package/llm-docs/principles-and-architecture/thinking-in-graphql.mdx +309 -0
- package/llm-docs/principles-and-architecture/thinking-in-relay.mdx +104 -0
- package/llm-docs/principles-and-architecture/videos.mdx +50 -0
- package/llm-docs/tutorial/arrays-lists.mdx +126 -0
- package/llm-docs/tutorial/fragments-1.mdx +487 -0
- package/llm-docs/tutorial/graphql.mdx +172 -0
- package/llm-docs/tutorial/interfaces-polymorphism.mdx +161 -0
- package/llm-docs/tutorial/intro.mdx +58 -0
- package/llm-docs/tutorial/mutations-updates.mdx +624 -0
- package/llm-docs/tutorial/organizing-mutations-queries-and-subscriptions.mdx +13 -0
- package/llm-docs/tutorial/queries-1.mdx +267 -0
- package/llm-docs/tutorial/queries-2.mdx +389 -0
- package/llm-docs/tutorial/refetchable-fragments.mdx +352 -0
- package/multi-actor-environment/ActorIdentifier.js.flow +2 -2
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +7 -7
- package/multi-actor-environment/ActorUtils.js.flow +1 -1
- package/multi-actor-environment/MultiActorEnvironment.js.flow +12 -8
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +3 -3
- package/mutations/RelayDeclarativeMutationConfig.js.flow +9 -9
- package/mutations/RelayRecordProxy.js.flow +8 -11
- package/mutations/RelayRecordSourceMutator.js.flow +4 -4
- package/mutations/RelayRecordSourceProxy.js.flow +4 -4
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +6 -6
- package/mutations/applyOptimisticMutation.js.flow +2 -2
- package/mutations/commitMutation.js.flow +20 -16
- package/mutations/createUpdatableProxy.js.flow +19 -19
- package/mutations/readUpdatableFragment.js.flow +3 -3
- package/mutations/readUpdatableQuery.js.flow +3 -3
- package/mutations/validateMutation.js.flow +7 -7
- package/network/RelayNetworkTypes.js.flow +4 -4
- package/network/RelayObservable.js.flow +16 -14
- package/network/RelayQueryResponseCache.js.flow +3 -3
- package/network/wrapNetworkWithLogObserver.js.flow +1 -1
- package/package.json +2 -1
- package/query/GraphQLTag.js.flow +22 -10
- package/query/fetchQuery.js.flow +23 -10
- package/query/fetchQuery_DEPRECATED.js.flow +1 -1
- package/store/DataChecker.js.flow +43 -9
- package/store/NormalizationEngine.js.flow +779 -0
- package/store/OperationExecutor.js.flow +173 -70
- package/store/RelayConcreteVariables.js.flow +5 -5
- package/store/RelayErrorTrie.js.flow +12 -12
- package/store/RelayExperimentalGraphResponseHandler.js.flow +3 -3
- package/store/RelayExperimentalGraphResponseTransform.js.flow +10 -10
- package/store/RelayModernEnvironment.js.flow +41 -26
- package/store/RelayModernFragmentSpecResolver.js.flow +1 -1
- package/store/RelayModernOperationDescriptor.js.flow +1 -1
- package/store/RelayModernRecord.js.flow +46 -22
- package/store/RelayModernSelector.js.flow +21 -21
- package/store/RelayModernStore.js.flow +219 -58
- package/store/RelayOperationTracker.js.flow +2 -2
- package/store/RelayOptimisticRecordSource.js.flow +2 -2
- package/store/RelayPublishQueue.js.flow +21 -12
- package/store/RelayReader.js.flow +130 -58
- package/store/RelayRecordSource.js.flow +10 -0
- package/store/RelayRecordState.js.flow +1 -1
- package/store/RelayReferenceMarker.js.flow +5 -4
- package/store/RelayResponseNormalizer.js.flow +130 -54
- package/store/RelayStoreSubscriptions.js.flow +52 -8
- package/store/RelayStoreTypes.js.flow +153 -64
- package/store/RelayStoreUtils.js.flow +15 -7
- package/store/ResolverCache.js.flow +2 -2
- package/store/ResolverFragments.js.flow +12 -12
- package/store/StoreInspector.js.flow +6 -7
- package/store/cloneRelayHandleSourceField.js.flow +1 -1
- package/store/cloneRelayScalarHandleSourceField.js.flow +1 -1
- package/store/createRelayContext.js.flow +1 -1
- package/store/createRelayLoggingContext.js.flow +4 -4
- package/store/defaultGetDataID.js.flow +2 -2
- package/store/isRelayModernEnvironment.js.flow +4 -2
- package/store/live-resolvers/LiveResolverCache.js.flow +55 -20
- package/store/live-resolvers/LiveResolverSuspenseSentinel.js.flow +3 -3
- package/store/live-resolvers/getOutputTypeRecordIDs.js.flow +1 -1
- package/store/live-resolvers/isLiveStateValue.js.flow +2 -2
- package/store/live-resolvers/resolverDataInjector.js.flow +8 -5
- package/store/observeFragmentExperimental.js.flow +49 -20
- package/store/observeQueryExperimental.js.flow +5 -5
- package/store/readInlineData.js.flow +4 -4
- package/store/waitForFragmentExperimental.js.flow +3 -3
- package/subscription/requestSubscription.js.flow +7 -7
- package/util/NormalizationNode.js.flow +34 -32
- package/util/ReaderNode.js.flow +32 -30
- package/util/RelayConcreteNode.js.flow +5 -5
- package/util/RelayError.js.flow +4 -1
- package/util/RelayFeatureFlags.js.flow +21 -1
- package/util/RelayProfiler.js.flow +1 -1
- package/util/RelayReplaySubject.js.flow +3 -3
- package/util/RelayRuntimeTypes.js.flow +11 -11
- package/util/createPayloadFor3DField.js.flow +9 -5
- package/util/deepFreeze.js.flow +2 -2
- package/util/getFragmentIdentifier.js.flow +1 -1
- package/util/getPaginationMetadata.js.flow +1 -1
- package/util/getPaginationVariables.js.flow +1 -1
- package/util/getPendingOperationsForFragment.js.flow +2 -2
- package/util/getRefetchMetadata.js.flow +6 -5
- package/util/getValueAtPath.js.flow +3 -3
- package/util/handlePotentialSnapshotErrors.js.flow +5 -5
- package/util/isEmptyObject.js.flow +1 -1
- package/util/isPromise.js.flow +2 -2
- package/util/isScalarAndEqual.js.flow +1 -1
- package/util/recycleNodesInto.js.flow +2 -2
- package/util/registerEnvironmentWithDevTools.js.flow +1 -1
- package/util/shallowFreeze.js.flow +1 -1
- package/util/stableCopy.js.flow +5 -5
- package/util/withProvidedVariables.js.flow +14 -10
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: wait-for-fragment-data
|
|
3
|
+
title: waitForFragmentData
|
|
4
|
+
slug: /api-reference/wait-for-fragment-data/
|
|
5
|
+
description: Read the value of a fragment as a promise
|
|
6
|
+
keywords:
|
|
7
|
+
- promise
|
|
8
|
+
- fragment
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
12
|
+
|
|
13
|
+
:::warning
|
|
14
|
+
`waitForFragmentData` is still an experimental API. It currently has some limitations and may evolve slightly during this phase.
|
|
15
|
+
:::
|
|
16
|
+
|
|
17
|
+
## `waitForFragmentData`
|
|
18
|
+
|
|
19
|
+
In some cases it can be useful to define data that you wish to read using a GraphQL fragment, but then consume it just once outside of React render function. `waitForFragmentData` allows you to wait for the data of a fragment to be available,
|
|
20
|
+
|
|
21
|
+
To read a fragment's data as it changes over time, see [`observeFragment`](./observe-fragment.mdx).
|
|
22
|
+
|
|
23
|
+
### Example: Deferring data used in an event handler
|
|
24
|
+
|
|
25
|
+
One use case for `waitForFragmentData` is to defer fetching data that is needed inside an event handler, but is not needed to render the initial view.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { useCallback } from "react";
|
|
29
|
+
import { useFragment } from "react-relay";
|
|
30
|
+
import { graphql } from "relay-runtime";
|
|
31
|
+
import { waitForFragmentData } from "relay-runtime/experimental";
|
|
32
|
+
|
|
33
|
+
function MyComponent({ key }) {
|
|
34
|
+
const user = useFragment(
|
|
35
|
+
graphql`
|
|
36
|
+
fragment UserFragment on User {
|
|
37
|
+
name
|
|
38
|
+
# Page load can complete before this data has streamed in from the server.
|
|
39
|
+
...EventHandlerFragment @defer
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
key,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const onClick = useCallback(async () => {
|
|
46
|
+
// Once the user clicks, we may need to wait for the data to finish loading.
|
|
47
|
+
const userData = await waitForFragmentData(
|
|
48
|
+
graphql`
|
|
49
|
+
fragment EventHandlerFragment on User {
|
|
50
|
+
age
|
|
51
|
+
}
|
|
52
|
+
`,
|
|
53
|
+
user,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (userData.age < 10) {
|
|
57
|
+
alert("Hello kiddo!");
|
|
58
|
+
} else if (userData.age < 18) {
|
|
59
|
+
alert("Hello young person!");
|
|
60
|
+
} else {
|
|
61
|
+
alert("Hello adult person!");
|
|
62
|
+
}
|
|
63
|
+
}, [user]);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
My name is {user.name}
|
|
68
|
+
<button onClick={onClick}>Greet</button>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Arguments
|
|
75
|
+
|
|
76
|
+
* `environment`: `IEnvironment`. A Relay environment.
|
|
77
|
+
* `fragment`: GraphQL fragment specified using a `graphql` template literal.
|
|
78
|
+
* `fragmentReference`: The *fragment reference* is an opaque Relay object that Relay uses to read the data for the fragment from the store; more specifically, it contains information about which particular object instance the data should be read from.
|
|
79
|
+
* The type of the fragment reference can be imported from the generated Flow types, from the file `<fragment_name>.graphql.js`, and can be used to declare the type of your `Props`. The name of the fragment reference type will be: `<fragment_name>$key`. We use our [lint rule](https://github.com/relayjs/eslint-plugin-relay) to enforce that the type of the fragment reference prop is correctly declared.
|
|
80
|
+
|
|
81
|
+
### Return Value
|
|
82
|
+
|
|
83
|
+
* A `Promise<T>` where `T` is the data defined in the fragment.
|
|
84
|
+
|
|
85
|
+
The Promise will wait for all network data to become available as well as any [`@live` Relay Resolver](../../guides/relay-resolvers/live-fields.mdx) to be in a non-suspended state before it resolves.
|
|
86
|
+
|
|
87
|
+
In the case of a network error, or a field-level error due to [`@throwOnFieldError`](../../guides/throw-on-field-error-directive.mdx) or [`@required(action: THROW)`](../../guides/required-directive.mdx), the Promise will reject with an error.
|
|
88
|
+
|
|
89
|
+
<DocsRating />
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#### Type `CacheConfig`
|
|
2
|
+
|
|
3
|
+
* An object with the following fields:
|
|
4
|
+
* `force`: *_[Optional]_* A boolean. If true, causes a query to be issued unconditionally, regardless of the state of any configured response cache.
|
|
5
|
+
* `poll`: *_[Optional]_* A number. Causes a query to live-update by polling at the specified interval, in milliseconds. (This value will be passed to `setTimeout`).
|
|
6
|
+
* `liveConfigId`: *_[Optional]_* A string. Causes a query to live-update by calling GraphQLLiveQuery; it represents a configuration of gateway when doing live query.
|
|
7
|
+
* `metadata`: *_[Optional]_* An object. User-supplied metadata.
|
|
8
|
+
* `transactionId`: *_[Optional]_* A string. A user-supplied value, intended for use as a unique id for a given instance of executing an operation.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import SelectorStoreUpdater from './SelectorStoreUpdater.mdx';
|
|
2
|
+
import CacheConfig from './CacheConfig.mdx';
|
|
3
|
+
|
|
4
|
+
#### Type `GraphQLSubscriptionConfig<TSubscriptionPayload>`
|
|
5
|
+
|
|
6
|
+
* An object with the following fields:
|
|
7
|
+
* `cacheConfig`: *_[Optional]_* [`CacheConfig`](#type-cacheconfig)
|
|
8
|
+
* `subscription`: `GraphQLTaggedNode`. A GraphQL subscription specified using a `graphql` template literal
|
|
9
|
+
* `variables`: The variables to pass to the subscription
|
|
10
|
+
* `onCompleted`: *_[Optional]_* `() => void`. An optional callback that is executed when the subscription is established
|
|
11
|
+
* `onError`: *_[Optional]_* `(Error) => {}`. An optional callback that is executed when an error occurs
|
|
12
|
+
* `onNext`: *_[Optional]_* `(TSubscriptionPayload) => {}`. An optional callback that is executed when new data is received
|
|
13
|
+
* `updater`: *_[Optional]_* [`SelectorStoreUpdater`](#type-selectorstoreupdater).
|
|
14
|
+
|
|
15
|
+
<CacheConfig />
|
|
16
|
+
|
|
17
|
+
<SelectorStoreUpdater />
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import CacheConfig from './CacheConfig.mdx';
|
|
2
|
+
import SelectorStoreUpdater from './SelectorStoreUpdater.mdx';
|
|
3
|
+
import UploadableMap from './UploadableMap.mdx';
|
|
4
|
+
|
|
5
|
+
#### Type `MutationConfig<TMutationConfig: MutationParameters>`
|
|
6
|
+
|
|
7
|
+
* An object with the following fields:
|
|
8
|
+
* `cacheConfig`: *_[Optional]_* [`CacheConfig`](#type-cacheconfig)
|
|
9
|
+
* `mutation`: `GraphQLTaggedNode`. A mutation specified using a GraphQL literal
|
|
10
|
+
* `onError`: *_[Optional]_* `(Error) => void`. An optional callback executed if the mutation results in an error.
|
|
11
|
+
* `onCompleted`: *_[Optional]_* `($ElementType<TMutationConfig, 'response'>) => void`. An optional callback that is executed when the mutation completes.
|
|
12
|
+
* The value passed to `onCompleted` is the the mutation fragment, as read out from the store, **after** updaters and declarative mutation directives are applied. This means that data from within unmasked fragments will not be read, and records that were deleted (e.g. by `@deleteRecord`) may also be null.
|
|
13
|
+
* `onUnsubscribe`: *_[Optional]_* `() => void`. An optional callback that is executed when the mutation is unsubscribed, which occurs when the returned `Disposable` is disposed.
|
|
14
|
+
* `optimisticResponse`: *_[Optional]_* An object whose type matches the raw response type of the mutation. Make sure you decorate your mutation with `@raw_response_type` if you are using this field.
|
|
15
|
+
* `optimisticUpdater`: *_[Optional]_* [`SelectorStoreUpdater`](#type-selectorstoreupdater). A callback that is executed when `commitMutation` is called, after the `optimisticResponse` has been normalized into the store.
|
|
16
|
+
* `updater`: *_[Optional]_* [`SelectorStoreUpdater`](#type-selectorstoreupdater). A callback that is executed when a payload is received, after the payload has been written into the store.
|
|
17
|
+
* `uploadables`: *_[Optional]_* [`UploadableMap`](#type-uploadablemap). An optional uploadable map.
|
|
18
|
+
* `variables`: `$ElementType<TMutationConfig, 'variables'>`. The variables to pass to the mutation.
|
|
19
|
+
|
|
20
|
+
<CacheConfig />
|
|
21
|
+
|
|
22
|
+
<SelectorStoreUpdater />
|
|
23
|
+
|
|
24
|
+
<UploadableMap />
|
|
25
|
+
|
|
26
|
+
#### Type `MutationParameters`
|
|
27
|
+
|
|
28
|
+
* An object with the following fields:
|
|
29
|
+
* `response`: An object
|
|
30
|
+
* `variables`: An object
|
|
31
|
+
* `rawResponse`: An optional object
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
2
|
+
|
|
3
|
+
#### Type `SelectorStoreUpdater`
|
|
4
|
+
|
|
5
|
+
* A function with signature `(store: RecordSourceSelectorProxy, data) => void`
|
|
6
|
+
* This interface allows you to *imperatively* write and read data directly to and from the Relay store. This means that you have full control over how to update the store in response to the subscription payload: you can *create entirely new records*, or *update or delete existing ones*. The full API for reading and writing to the Relay store is available <a href={useBaseUrl('docs/api-reference/store/#recordsourceselectorproxy')}>here</a>.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: learning-resources
|
|
3
|
+
title: Community Learning Resources
|
|
4
|
+
slug: /community-learning-resources/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
8
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
9
|
+
import {FbInternalOnly, OssOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
10
|
+
|
|
11
|
+
## Guides and articles:
|
|
12
|
+
|
|
13
|
+
- [How to use @argumentsDefinitions to define local variables to your fragments](https://medium.com/entria/relay-modern-argumentdefinitions-d53769dbb95d) (by Entria)
|
|
14
|
+
- [Deep Dive of Updater Relay Store function. How to update your store properly after a mutation or subscription](https://medium.com/entria/wrangling-the-client-store-with-the-relay-modern-updater-function-5c32149a71ac) (by Entria)
|
|
15
|
+
- [Optimistic Update: how to update your UI before server responds](https://medium.com/entria/relay-modern-optimistic-update-a09ba22d83c9) (by Entria)
|
|
16
|
+
- [Relay Network Deep Dive - how to incrementally improve your network layer to manage complex data fetching requirements](https://medium.com/entria/relay-modern-network-deep-dive-ec187629dfd3) (by Entria)
|
|
17
|
+
- [Relay Modern with TypeScript - how to configure Relay Modern to make it with TypeScript](https://medium.com/@sibelius/relay-modern-migration-to-typescript-c26ab0ee749c) (by @sibelius)
|
|
18
|
+
- [Collection of random thoughts and discoveries around Relay](https://mrtnzlml.com/docs/relay)
|
|
19
|
+
|
|
20
|
+
<OssOnly>
|
|
21
|
+
|
|
22
|
+
## Relay example projects
|
|
23
|
+
|
|
24
|
+
These projects serve as an example of how to use Relay in real world applications. Some of them are even with educational videos.
|
|
25
|
+
|
|
26
|
+
- [github.com/relayjs/relay-examples](https://github.com/relayjs/relay-examples)
|
|
27
|
+
- [github.com/adeira/relay-example](https://github.com/adeira/relay-example)
|
|
28
|
+
- [github.com/juffalow/react-relay-example](https://github.com/juffalow/react-relay-example)
|
|
29
|
+
|
|
30
|
+
## Learn basics
|
|
31
|
+
|
|
32
|
+
Here, you will find articles written by the Relay community. They touch on basic topics that are necessary for daily work.
|
|
33
|
+
|
|
34
|
+
- [What is a fragment? Basic explanation of what is a fragment and what it is used for](https://medium.com/@sibelius/relay-modern-what-is-a-fragment-c70f164c2469) (by @sibelius)
|
|
35
|
+
- [Relay anti-patterns. What you should avoid doing when using Relay concepts](https://medium.com/entria/relay-apollo-anti-pattern-d9f4dea47738) (by Entria)
|
|
36
|
+
- [Insights of how Relay Modern has improved a lot since Relay Classic](https://medium.com/entria/relay-is-just-getting-better-54112ffc1a9e) (by Entria)
|
|
37
|
+
- [How to use @argumentsDefinitions to define local variables to your fragments](https://medium.com/entria/relay-modern-argumentdefinitions-d53769dbb95d) (by Entria)
|
|
38
|
+
- [How to paginate using a Refetch Container. You can use a refetch container to paginate as well, just use renderVariables correctly](https://medium.com/entria/relay-modern-pagination-using-refetch-container-editing-a07c6b33ae4e) (by Entria)
|
|
39
|
+
|
|
40
|
+
## About Relay Store
|
|
41
|
+
|
|
42
|
+
- [How Relay Modern stores your data](https://medium.com/@sibelius/relay-modern-the-relay-store-8984cd148798) (by @sibelius)
|
|
43
|
+
- [Deep Dive of Updater Relay Store function. How to update your store properly after a mutation or subscription](https://medium.com/entria/wrangling-the-client-store-with-the-relay-modern-updater-function-5c32149a71ac) (by Entria)
|
|
44
|
+
- [Optimistic Update: how to update your UI before server responds](https://medium.com/entria/relay-modern-optimistic-update-a09ba22d83c9) (by Entria)
|
|
45
|
+
- [Local State Management, part 1 - how to create a controlled input using Relay](https://babangsund.com/relay_local_state_management/) (by @babangsund)
|
|
46
|
+
- [Local State Management, part 2 - how to manage global state and localStorage persistence on the client, using Relay](https://babangsund.com/relay_local_state_management_2/) (by @babangsund)
|
|
47
|
+
- [Local State Management, part 3 - using LocalQueryRenderer and local state to manage nested fragments](https://babangsund.com/relay_local_state_management_3/) (by @babangsund)
|
|
48
|
+
|
|
49
|
+
## Network Layer
|
|
50
|
+
|
|
51
|
+
- [Relay Network Deep Dive - how to incrementally improve your network layer to manage complex data fetching requirements](https://medium.com/entria/relay-modern-network-deep-dive-ec187629dfd3) (by Entria)
|
|
52
|
+
|
|
53
|
+
## Relay Configuration
|
|
54
|
+
|
|
55
|
+
- [Relay Modern with TypeScript - how to configure Relay Modern to make it with TypeScript](https://medium.com/@sibelius/relay-modern-migration-to-typescript-c26ab0ee749c) (by @sibelius)
|
|
56
|
+
|
|
57
|
+
## Miscellaneous
|
|
58
|
+
|
|
59
|
+
- [Relay Modern Learning Blog Posts Thread on Twitter](https://twitter.com/sseraphini/status/1078595758801203202)
|
|
60
|
+
- [Collection of random thoughts and discoveries around Relay](https://mrtnzlml.com/docs/relay)
|
|
61
|
+
|
|
62
|
+
</OssOnly>
|
|
63
|
+
|
|
64
|
+
<DocsRating />
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: declarative-mutation-directives
|
|
3
|
+
title: Debugging Declarative Mutation Directives
|
|
4
|
+
slug: /debugging/declarative-mutation-directives/
|
|
5
|
+
description: Debugging declarative mutation directives
|
|
6
|
+
keywords:
|
|
7
|
+
- debugging
|
|
8
|
+
- troubleshooting
|
|
9
|
+
- declarative mutation directive
|
|
10
|
+
- deleteRecord
|
|
11
|
+
- handlerProvider
|
|
12
|
+
- appendEdge
|
|
13
|
+
- prependEdge
|
|
14
|
+
- appendNode
|
|
15
|
+
- prependNode
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
// @fb-only
|
|
19
|
+
|
|
20
|
+
If you see an error similar to:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
RelayFBHandlerProvider: No handler defined for `deleteRecord`. [Caught in: An uncaught error was thrown inside `RelayObservable`.]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
or
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
RelayModernEnvironment: Expected a handler to be provided for handle `deleteRecord`.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This probably means that you are using a Relay environment to which a `handlerProvider` is passed. However, the handler provider does not know how to accept the handles `"deleteRecord"`, `"appendEdge"` or `"prependEdge"`. If this is the case, you should return `MutationHandlers.DeleteRecordHandler`, `MutationHandlers.AppendEdgeHandler`, or `MutationHandlers.PrependEdgeHandler` respectively (these can be imported from `relay-runtime`).
|
|
33
|
+
|
|
34
|
+
// @fb-only
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: disallowed-id-types-error
|
|
3
|
+
title: Disallowed Types for `id` Fields
|
|
4
|
+
slug: /debugging/disallowed-id-types-error
|
|
5
|
+
description: Disallowed types for `id` fields
|
|
6
|
+
keywords:
|
|
7
|
+
- debugging
|
|
8
|
+
- troubleshooting
|
|
9
|
+
- disallowed
|
|
10
|
+
- id
|
|
11
|
+
- Object Identification
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
15
|
+
|
|
16
|
+
If you see an error from the compiler that reads something like:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Disallowed type `String` of field `id` on parent type `Foo` cannot be used by Relay to identify entities
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This means that your GraphQL schema defines an object with a field named `id` that doesn't have a valid type. Valid types for this field are `ID` or `ID!` unless configured otherwise. While there may be a valid reason in your application to have that field defined that way, the Relay compiler and runtime will mishandle that field and cause refresh or data updating issues.
|
|
23
|
+
|
|
24
|
+
## Disallowing `id` fields without type `ID`
|
|
25
|
+
|
|
26
|
+
Recall that Relay uses [Object Identification](../../guides/graphql-server-specification/#object-identification) to know which GraphQL objects to refetch. In the usual case, those GraphQL objects implement the [`Node` interface](https://graphql.org/learn/global-object-identification/#node-interface) and thus come with an `id` field with type `ID`. However, there are types in your GraphQL model that may not require unique identification. For that reason, Relay (by default) does not restrict object definitions, allowing `id` fields with non-`ID` types (e.g. `String`) to be defined.
|
|
27
|
+
|
|
28
|
+
This poses a bit of difficulty to both Relay's compiler and runtime. In short, the runtime and compiler only properly handle `id` fields as defined by the `Node` interface. Any selections made with non-`Node` `id` fields will likely exhibit undesirable and unintended Relay behavior on your components (e.g. components not re-rendering on re-fetched data).
|
|
29
|
+
|
|
30
|
+
### The significance of the `ID` type
|
|
31
|
+
|
|
32
|
+
[Global Object Identification in GraphQL](https://graphql.org/learn/global-object-identification/)) is what underlies Relay's Object Identification. The `id` field supplied by the `Node` interface is specified to be a unique identifier that can be used for storage or caching.
|
|
33
|
+
|
|
34
|
+
## Fix: Define your `id` fields as `ID`
|
|
35
|
+
|
|
36
|
+
To ensure Relay correctly manages objects fetched to your application, here are two recommended courses of action:
|
|
37
|
+
|
|
38
|
+
* Ensure all fields named `id` are typed with `ID`
|
|
39
|
+
* Rename any fields named `id` (with a type that isn't `ID`) to a different name (e.g. `special_purpose_id`)
|
|
40
|
+
|
|
41
|
+
If your application truly requires that `id` field's definition to remain as-is and you are aware of the problems that may arise, you can add your GraphQL type and the type of its `id` field to the allowlist in `nonNodeIdFields` of the [Relay Compiler's Configuration](https://github.com/facebook/relay/tree/main/packages/relay-compiler). Note that this will only bypass the error for that combination of object type and `id` field type.
|
|
42
|
+
|
|
43
|
+
<DocsRating />
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: inconsistent-typename-error
|
|
3
|
+
title: Inconsistent Typename Error
|
|
4
|
+
slug: /debugging/inconsistent-typename-error/
|
|
5
|
+
description: Debugging inconsistent typename errors in Relay
|
|
6
|
+
keywords:
|
|
7
|
+
- debugging
|
|
8
|
+
- troubleshooting
|
|
9
|
+
- inconsistent typename
|
|
10
|
+
- RelayResponseNormalizer
|
|
11
|
+
- globally unique id
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
15
|
+
import {FbInternalOnly, OssOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
16
|
+
|
|
17
|
+
## Inconsistent `__typename` error
|
|
18
|
+
|
|
19
|
+
The GraphQL server likely violated the globally unique ID requirement by returning the same ID for different objects.
|
|
20
|
+
|
|
21
|
+
If you're seeing an error like:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
`RelayResponseNormalizer: Invalid record '543'. Expected __typename to be consistent, but the record was assigned conflicting types Foo and Bar. The GraphQL server likely violated the globally unique ID requirement by returning the same ID for different objects.`
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
the server implementation of one of the types is not spec compliant. We require the `id` field to be globally unique. This is a problem because Relay stores objects in a normalized key-value store and one of the object just overwrote the other. This means your app is broken in some subtle or less subtle way.
|
|
28
|
+
|
|
29
|
+
## Common cause
|
|
30
|
+
|
|
31
|
+
The most common reason for this error is that 2 objects backed by an ID are using the plain ID as the id field, such as a `User` and `MessagingParticipant`.
|
|
32
|
+
|
|
33
|
+
Less common reasons could be using array indices or auto-increment IDs from some database that might not be unique to this type.
|
|
34
|
+
|
|
35
|
+
## Fix: Make your type spec compliant
|
|
36
|
+
|
|
37
|
+
The best way to fix this is to make your type spec compliant. For the case of 2 different types backed by the same ID, a common solution is to prefix the ID of the less widely used type with a unique string and then base64 encode the result. This can be accomplished fairly easily by implementing a `NodeTokenResolver` using the helper trait `NodeTokenResolverWithPrefix`. When the `NodeTokenResolver` is registered it allows you to load your type using `node(id: $yourID)` GraphQL call and your type can return an encoded ID.
|
|
38
|
+
|
|
39
|
+
<FbInternalOnly>
|
|
40
|
+
|
|
41
|
+
### Example
|
|
42
|
+
|
|
43
|
+
See [D17996531](https://www.internalfb.com/diff/D17996531) for an example on how to fix this. It created a `FusionPlatformComponentsCategoryNodeResolver` added the trait `TGraphQLNodeMixin` to the conflicting class so that it generates the base64 encoded ID.
|
|
44
|
+
|
|
45
|
+
</FbInternalOnly>
|
|
46
|
+
|
|
47
|
+
<DocsRating />
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: relay-devtools
|
|
3
|
+
title: Relay DevTools
|
|
4
|
+
slug: /debugging/relay-devtools/
|
|
5
|
+
description: Debugging guide for the Relay DevTools
|
|
6
|
+
keywords:
|
|
7
|
+
- debugging
|
|
8
|
+
- troubleshooting
|
|
9
|
+
- extension
|
|
10
|
+
- devtools
|
|
11
|
+
- browser
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
15
|
+
import {FbInternalOnly, OssOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
<FbInternalOnly>
|
|
20
|
+
|
|
21
|
+
### Internal version (preferred)
|
|
22
|
+
|
|
23
|
+
The internal version of devtools has the latest updates and the process of installation will be much faster.
|
|
24
|
+
|
|
25
|
+
1. Before downloading the new Devtools, make sure you've deleted all older versions of the extension.
|
|
26
|
+
2. Join [Relay Support](https://fb.workplace.com/groups/relay.support) group and you will automatically be added to the `cpe_relay_devtools_extension` gatekeeper.
|
|
27
|
+
3. Wait 20-30 minutes, and it should be downloaded on your Chrome browser
|
|
28
|
+
4. Or run `sudo soloctl -i` on your machine to get the extension immediately
|
|
29
|
+
|
|
30
|
+
### Internal Version for Edgium users
|
|
31
|
+
|
|
32
|
+
1. On `C:\Users\<User>\AppData\Local\Google\Chrome\User Data\<Work Profile>\Extensions` search for files manifest.json with Relay Developer Tools on it
|
|
33
|
+
2. Get the path to this folder e.g `...\Extensions\<blob>\<version>\`
|
|
34
|
+
3. On edge://extensions/ click load upacked (you might need to Allow extensions for other stores).
|
|
35
|
+
|
|
36
|
+
### External version (use at your own risk)
|
|
37
|
+
|
|
38
|
+
The external version of Dev Tools does not always contain the latest updates, it may stop working, potentially being restricted to be used or removed by corp device admin (via MDM).
|
|
39
|
+
We recommend using the internal installation, but if you prefer, you may download the extension from the [Chrome store](https://chrome.google.com/webstore/detail/relay-developer-tools/ncedobpgnmkhcmnnkcimnobpfepidadl).
|
|
40
|
+
|
|
41
|
+
</FbInternalOnly>
|
|
42
|
+
|
|
43
|
+
<OssOnly>
|
|
44
|
+
|
|
45
|
+
Follow this link and install it from the [chrome store](https://chrome.google.com/webstore/detail/relay-developer-tools/ncedobpgnmkhcmnnkcimnobpfepidadl).
|
|
46
|
+
|
|
47
|
+
</OssOnly>
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## How to Navigate the Relay DevTools Extension
|
|
52
|
+
|
|
53
|
+
You should have a new tab called Relay in your Chrome DevTools. In this tab, you will be able to select between 2 panels: the **network panel** and the **store panel**.
|
|
54
|
+
|
|
55
|
+
### Network Panel
|
|
56
|
+
|
|
57
|
+
The network panel allows users to view individual requests in an active environment. Users can scroll through these requests, search for the requests and view the details of each request. The details of each request includes the status, the variables, and the responses for the request.
|
|
58
|
+
|
|
59
|
+
### Store Panel
|
|
60
|
+
|
|
61
|
+
The store panel allows users to view individual records from the store data in an active environment. Users can scroll through these records, search for the records, and view the details of each request. Users can also copy the store data in JSON format to the clipboard. The details of each record includes the ID, the typename, and all of the data in the record. If one of the fields in the data is a reference to another record, users can click on the reference, which will take them to that record.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Multiple Environments
|
|
66
|
+
|
|
67
|
+
As you switch through the store and network panels, you'll notice that there is also a dropdown menu on the left side of the developer tools. This dropdown allows users to switch between environments. The requests in the network tab and the store data are grouped by environment, so users can easily shuffle between active environments.
|
|
68
|
+
|
|
69
|
+
## Give Feedback
|
|
70
|
+
|
|
71
|
+
Look in the top-right corner of the extension panel!
|
|
72
|
+
|
|
73
|
+
<DocsRating />
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: why-null
|
|
3
|
+
title: "Why Is My Field Null?"
|
|
4
|
+
slug: /debugging/why-null/
|
|
5
|
+
description: Get help figuring out why a given field is unexpectedly null.
|
|
6
|
+
keywords:
|
|
7
|
+
- "null"
|
|
8
|
+
- missing
|
|
9
|
+
- optional
|
|
10
|
+
- nullthrows
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
import {FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
14
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
15
|
+
|
|
16
|
+
There are a number of reasons that a field read by Relay can be null and some of them are obscure or unintuitive. When debugging an unexpectedly null value, it can be helpful to understand both the common cases and edge cases that can cause a field to be read as null. This document enumerates the cases that can lead to null or missing values with tips for determining which case you are in.
|
|
17
|
+
|
|
18
|
+
## Server Returned Null
|
|
19
|
+
|
|
20
|
+
The simplest reason a field might be null is that the server explicitly returned null. This can happen in two cases:
|
|
21
|
+
|
|
22
|
+
1. The server’s field resolver returned an explicit null
|
|
23
|
+
2. The field resolver throws. In this case GraphQL will return null for that field. *This is true even if the server resolver’s return type is non-nullable.* The one exception is fields annotated as non-null. In that case server should *never* return null. If an exception is encountered the entire parent object will be nulled out.
|
|
24
|
+
|
|
25
|
+
<FbInternalOnly>
|
|
26
|
+
|
|
27
|
+
:::note
|
|
28
|
+
At Meta, non-nullable fields are implemented using [`KillsParentOnException`](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/fields/return-type/#non-nullable-fields).
|
|
29
|
+
:::
|
|
30
|
+
|
|
31
|
+
</FbInternalOnly>
|
|
32
|
+
|
|
33
|
+
**🕵️♀️ How to tell:** Inspect the server’s response using Relay Dev tools, or in your browser’s dev tools’s network tab, to see if the field is null.
|
|
34
|
+
|
|
35
|
+
## Graph Relationship Change
|
|
36
|
+
|
|
37
|
+
If a different query/mutation/subscription observes a relationship change in the graph, you may end up trying to read fields off of an object which your query never fetched.
|
|
38
|
+
|
|
39
|
+
Imagine you have a query that reads your best friend’s name:
|
|
40
|
+
|
|
41
|
+
```graphql
|
|
42
|
+
query MyQuery {
|
|
43
|
+
me {
|
|
44
|
+
best_friend {
|
|
45
|
+
# id: 1
|
|
46
|
+
name
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
After you get your query response, *who* your best friend is *changes* on the server. Then a *different* query/mutation/subscription fetches a different set of fields off of `best_friend`.
|
|
53
|
+
|
|
54
|
+
```graphql
|
|
55
|
+
query OtherQuery {
|
|
56
|
+
me {
|
|
57
|
+
best_friend {
|
|
58
|
+
# new id: 2
|
|
59
|
+
# Note: name is not fetched here
|
|
60
|
+
age
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Because the Relay store is normalized, we will update the `me` record to indicate that `best_friend` linked field now points to the user with ID 2, and the only information we know about that user is their age.
|
|
67
|
+
|
|
68
|
+
This will trigger a rerender of `MyQuery`. However, when we try to read the `name` field off of the user with ID 2, we won’t find it, since the only thing we know about the user with ID 2 is their `age`. Note that a relationship “change” in this case, could also mean a relationship that is new. For example, if you start with no best friend but a subsequent response returns *some* best friend, but does not fetch all fields your component needs.
|
|
69
|
+
|
|
70
|
+
**Note**: In theory, Relay *could* refetch your query when this state is encountered, but some queries are not safe to re-issue arbitrarily, and more generally, UI state changing in a way that’s not tied to a direct user action can lead to confusion. For this reason, we have chosen not to perform refetches in this scenario.
|
|
71
|
+
|
|
72
|
+
**🕵️♀️ How to tell:** You can place a breakpoint/`console.log` at the finale return statement of `readWithIdentifier` in `FragmentResource` ([code pointer](https://github.com/facebook/relay/blob/2b9876fcbf0845cd23728d4d720712525ff424c4/packages/react-relay/relay-hooks/FragmentResource.js#L475). This is the point in Relay at which we know that we are missing data, but there is not query in flight to get it.
|
|
73
|
+
|
|
74
|
+
## Inconsistent Server Response
|
|
75
|
+
|
|
76
|
+
This is a **rare edge case**, *but* if the server does not correctly implement the [field stability](https://graphql.org/learn/global-object-identification/#field-stability) semantics of the id field, it’s possible that a field could be present in one part of the response, but *explicitly null* in another.
|
|
77
|
+
|
|
78
|
+
```graphql
|
|
79
|
+
{
|
|
80
|
+
me {
|
|
81
|
+
id: 1
|
|
82
|
+
name: "Alice"
|
|
83
|
+
}
|
|
84
|
+
me_elsewhere_in_the_graph {
|
|
85
|
+
id: 1 # Note this is the same as the `me` field above...
|
|
86
|
+
name: null
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
In this case, Relay first learns that user 1’s `name` is Alice, but later in the query finds that user 1’s `name` has now `null`. Because Relay stores data in a normalized store, user 1 can only have one value for `name` and Relay will end in a state where user 1’s `name` is `null`.
|
|
92
|
+
|
|
93
|
+
**🕵️♀️ How to tell:** Relay is smart enough to detect when this has happened, and will [log an error to the console](https://github.com/facebook/relay/blob/2b9876fcbf0845cd23728d4d720712525ff424c4/packages/relay-runtime/store/RelayResponseNormalizer.js#L505) in dev that looks like: “RelayResponseNormalizer: Invalid record. The record contains two instances of the same id: 1 with conflicting field, name and its values: Alice and null.". Additionally, you can manually inspect the query response.
|
|
94
|
+
|
|
95
|
+
Note that if the unstable field is a linked field (edge to another object), this type of bug can cause a Graph Relationship Change (described above) to occur *within a single response*. For example, if a user with the same `id` appears in two places in the response, but their `best_friend` is different in those two locations.
|
|
96
|
+
|
|
97
|
+
**🕵️♀️ How to tell:** Relay is also smart enough to detect this case, and will show a [similar console warning](https://github.com/facebook/relay/blob/2b9876fcbf0845cd23728d4d720712525ff424c4/packages/relay-runtime/store/RelayResponseNormalizer.js#L844) in dev.
|
|
98
|
+
|
|
99
|
+
<FbInternalOnly>
|
|
100
|
+
|
|
101
|
+
:::note
|
|
102
|
+
Because these errors exist in the codebase and can cause noisy console output, these warnings are [disabled](https://www.internalfb.com/code/www/[5b26a6bd37e8]/html/shared/core/WarningFilter.js?lines=559) in dev mode.
|
|
103
|
+
:::
|
|
104
|
+
|
|
105
|
+
</FbInternalOnly>
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Client-side Deletion or Incomplete Update
|
|
109
|
+
|
|
110
|
+
Imperative store updates, or optimistic updates could have deleted the record or field. If an imperative store update, or optimistic update, writes a new record to the store, it may not supply a value for a field which you expected to be able to read. This is a fundamental problem, since an updater cannot statically know all the data that might be accessed off of a new object.
|
|
111
|
+
|
|
112
|
+
**🕵️♀️ How to tell:** Due to React and Relay’s batching, it’s not always possible to associate a component update with the store update that triggered it. Here, your best bet is to set a breakpoint in your component for when your value is null, and then use the Relay Dev Tools to look at the last few updates.
|
|
113
|
+
|
|
114
|
+
This can happen due to a newly created object which did not supply a specific field or, as mentioned above, an update which causes a new or changed relationship in the graph. In this case, use the “How do tell” tip from that section.
|
|
115
|
+
|
|
116
|
+
<DocsRating />
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: editor-support
|
|
3
|
+
title: Editor Support
|
|
4
|
+
slug: /editor-support/
|
|
5
|
+
keywords:
|
|
6
|
+
- LSP
|
|
7
|
+
- Language Server Protocol
|
|
8
|
+
- VS Code
|
|
9
|
+
- VSCode
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
13
|
+
|
|
14
|
+
*TL;DR: We have a [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=meta.relay)*
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
The Relay compiler has a rich understanding of the GraphQL embedded in your code. We want to use that understanding to improve the developer experience of writing apps with Relay. So, starting in [v14.0.0](https://github.com/facebook/relay/releases/tag/v14.0.0), the new Rust Relay compiler can provide language features directly in your code editor. This means:
|
|
19
|
+
|
|
20
|
+
#### Relay compiler errors surface as red squiggles directly in your editor
|
|
21
|
+
|
|
22
|
+
<img src={useBaseUrl('img/docs/editor-support/diagnostics.png')} />
|
|
23
|
+
|
|
24
|
+
#### Autocomplete throughout your GraphQL tagged template literals
|
|
25
|
+
|
|
26
|
+
<img src={useBaseUrl('img/docs/editor-support/autocomplete.png')} />
|
|
27
|
+
|
|
28
|
+
#### Hover to see type information and documentation about Relay-specific features
|
|
29
|
+
|
|
30
|
+
<img src={useBaseUrl('img/docs/editor-support/hover.png')} />
|
|
31
|
+
|
|
32
|
+
#### `@deprecated` fields are rendered using ~~strikethrough~~
|
|
33
|
+
|
|
34
|
+
<img src={useBaseUrl('img/docs/editor-support/deprecated.png')} />
|
|
35
|
+
|
|
36
|
+
#### Click-to-definition for fragments, fields and types
|
|
37
|
+
|
|
38
|
+
<img src={useBaseUrl('img/docs/editor-support/go-to-def.gif')} />
|
|
39
|
+
|
|
40
|
+
#### Quick fix suggestions for common errors
|
|
41
|
+
|
|
42
|
+
<img src={useBaseUrl('img/docs/editor-support/code-actions.png')} />
|
|
43
|
+
|
|
44
|
+
## Language Server
|
|
45
|
+
|
|
46
|
+
The editor support is implemented using the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) which means it can be used by a variety of editors, but in tandem with this release, [Terence Bezman](https://twitter.com/b_ez_man) from [Coinbase](https://www.coinbase.com/) has contributed an official VS Code extension.
|
|
47
|
+
|
|
48
|
+
[**Find it here!**](https://marketplace.visualstudio.com/items?itemName=meta.relay)
|
|
49
|
+
|
|
50
|
+
## Why Have a Relay-Specific Editor Extension?
|
|
51
|
+
|
|
52
|
+
The GraphQL foundation has an official language server and [VS Code extension](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql) which provides editor support for GraphQL generically. This can provide a good baseline experience, but for Relay users, getting this information directly from the Relay compiler offers a number of benefits:
|
|
53
|
+
|
|
54
|
+
* Relay compiler errors can surface directly in the editor as “problems”, often with suggested quick fixes
|
|
55
|
+
* Hover information is aware of Relay-specific features and directives and can link out to relevant documentation
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: unknown-field
|
|
3
|
+
title: "Why Is My Field Not Found?"
|
|
4
|
+
slug: /error-reference/unknown-field/
|
|
5
|
+
description: Get help figuring out why a given field is not found.
|
|
6
|
+
keywords:
|
|
7
|
+
- no such field on type
|
|
8
|
+
- missing
|
|
9
|
+
- field
|
|
10
|
+
- type
|
|
11
|
+
- compilation
|
|
12
|
+
- error
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
import {FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
16
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
17
|
+
|
|
18
|
+
## [ERROR] Error in the project `some_project`: ✖︎ The type `Some_Type` has no field `some_unknown_field`.
|
|
19
|
+
|
|
20
|
+
### Field name typo
|
|
21
|
+
|
|
22
|
+
In case of a missing field in a type, the Relay compiler tries to find and suggest a field replacement. For example: ```Error in the project `some_project`: ✖︎ The type `UserInfo` has no field `mail`. Did you mean `email`?```
|
|
23
|
+
|
|
24
|
+
<FbInternalOnly>
|
|
25
|
+
|
|
26
|
+
### The field exists in another schema
|
|
27
|
+
|
|
28
|
+
Relay Compiler uses schemas in order to resolve types and their fields. The type's schema is determined by the file path and the mapping from file path to schema, which is configured in the "schema" or "schemaDir" properties of your Relay compiler config. If you expect this field to exist, make sure you're using the right schema.
|
|
29
|
+
|
|
30
|
+
:::note
|
|
31
|
+
At meta there are various project config files that are listed [here](https://www.internalfb.com/intern/wiki/Relay-team/Rust_compiler_resources/#where-are-the-project-co).
|
|
32
|
+
:::
|
|
33
|
+
|
|
34
|
+
</FbInternalOnly>
|
|
35
|
+
|
|
36
|
+
<DocsRating />
|