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,245 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: loading-states
|
|
3
|
+
title: Loading States with Suspense
|
|
4
|
+
slug: /guided-tour/rendering/loading-states/
|
|
5
|
+
description: Relay guide to loading states
|
|
6
|
+
keywords:
|
|
7
|
+
- suspense
|
|
8
|
+
- loading
|
|
9
|
+
- glimmer
|
|
10
|
+
- fallback
|
|
11
|
+
- spinner
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
15
|
+
// @fb-only
|
|
16
|
+
import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
17
|
+
// @fb-only
|
|
18
|
+
// @fb-only
|
|
19
|
+
// @fb-only
|
|
20
|
+
// @fb-only
|
|
21
|
+
// @fb-only
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
As you may have noticed, we mentioned that using `usePreloadedQuery` and `useLazyLoadQuery` will render data from a query that was being fetched from the server, but we didn't elaborate on how to render a loading UI (such as a glimmer) while that data is still being fetched. We will cover that in this section.
|
|
25
|
+
|
|
26
|
+
<FbInternalOnly>
|
|
27
|
+
// @fb-only
|
|
28
|
+
</FbInternalOnly>
|
|
29
|
+
|
|
30
|
+
<OssOnly>
|
|
31
|
+
|
|
32
|
+
To render loading states while a query is being fetched, we rely on [React Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html). Suspense is a new feature in React that allows components to interrupt or *"suspend"* rendering in order to wait for some asynchronous resource (such as code, images or data) to be loaded; when a component "suspends", it indicates to React that the component isn't *"ready"* to be rendered yet, and won't be until the asynchronous resource it's waiting for is loaded. When the resource finally loads, React will try to render the component again.
|
|
33
|
+
|
|
34
|
+
</OssOnly>
|
|
35
|
+
|
|
36
|
+
This capability is useful for components to express asynchronous dependencies like data, code, or images that they require in order to render, and lets React coordinate rendering the loading states across a component tree as these asynchronous resources become available. More generally, the use of Suspense give us better control to implement more deliberately designed loading states when our app is loading for the first time or when it's transitioning to different states, and helps prevent accidental flickering of loading elements (such as spinners), which can commonly occur when loading sequences aren't explicitly designed and coordinated.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<FbInternalOnly>
|
|
40
|
+
// @fb-only
|
|
41
|
+
</FbInternalOnly>
|
|
42
|
+
|
|
43
|
+
## Loading fallbacks with Suspense Boundaries
|
|
44
|
+
|
|
45
|
+
When a component is suspended, we need to render a *fallback* in place of the component while we wait for it to become *"ready"*. In order to do so, we use the `Suspense` component provided by React:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
const React = require('React');
|
|
49
|
+
const {Suspense} = require('React');
|
|
50
|
+
|
|
51
|
+
function App() {
|
|
52
|
+
return (
|
|
53
|
+
// Render a fallback using Suspense as a wrapper
|
|
54
|
+
<Suspense fallback={<LoadingGlimmer />}>
|
|
55
|
+
<CanSuspend />
|
|
56
|
+
</Suspense>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
`Suspense` components can be used to wrap any component; if the target component suspends, `Suspense` will render the provided fallback until all its descendants become *"ready"* (i.e. until *all* of the suspended components within the subtree resolve). Usually, the fallback is used to render fallback loading states such as a glimmers and placeholders.
|
|
63
|
+
|
|
64
|
+
Usually, different pieces of content in our app might suspend, so we can show loading state until they are resolved by using `Suspense` :
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
/**
|
|
68
|
+
* App.react.js
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
const React = require('React');
|
|
72
|
+
const {Suspense} = require('React');
|
|
73
|
+
|
|
74
|
+
function App() {
|
|
75
|
+
return (
|
|
76
|
+
// LoadingGlimmer is rendered via the Suspense fallback
|
|
77
|
+
<Suspense fallback={<LoadingGlimmer />}>
|
|
78
|
+
<MainContent /> {/* MainContent may suspend */}
|
|
79
|
+
</Suspense>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
<FbInternalOnly>
|
|
85
|
+
// @fb-only
|
|
86
|
+
</FbInternalOnly>
|
|
87
|
+
|
|
88
|
+
Let's distill what's going on here:
|
|
89
|
+
|
|
90
|
+
* If `MainContent` suspends because it's waiting on some asynchronous resource (like data), the `Suspense` component that wraps `MainContent` will detect that it suspended, and will render the `fallback` element (i.e. the `LoadingGlimmer` in this case) up until `MainContent` is ready to be rendered. Note that this also transitively includes descendants of `MainContent`, which might also suspend.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
What's nice about Suspense is that you have granular control about how to accumulate loading states for different parts of your component tree:
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
/**
|
|
97
|
+
* App.react.js
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
const React = require('React');
|
|
101
|
+
const {Suspense} = require('React');
|
|
102
|
+
|
|
103
|
+
function App() {
|
|
104
|
+
return (
|
|
105
|
+
// A LoadingGlimmer for all content is rendered via the Suspense fallback
|
|
106
|
+
<Suspense fallback={<LoadingGlimmer />}>
|
|
107
|
+
<MainContent />
|
|
108
|
+
<SecondaryContent /> {/* SecondaryContent can also suspend */}
|
|
109
|
+
</Suspense>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
// @fb-only
|
|
115
|
+
|
|
116
|
+
* In this case, both `MainContent` and `SecondaryContent` may suspend while they load their asynchronous resources; by wrapping both in a `Suspense`, we can show a single loading state up until they are *all* ready, and then render the entire content in a single paint, after everything has successfully loaded.
|
|
117
|
+
* In fact, `MainContent` and `SecondaryContent` may suspend for different reasons other than fetching data, but the same `Suspense` component can be used to render a fallback up until *all* components in the subtree are ready to be rendered. Note that this also transitively includes descendants of `MainContent` or `SecondaryContent`, which might also suspend.
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
Conversely, you can also decide to be more granular about your loading UI and wrap Suspense components around smaller or individual parts of your component tree:
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
/**
|
|
124
|
+
* App.react.js
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
const React = require('React');
|
|
128
|
+
const {Suspense} = require('React');
|
|
129
|
+
|
|
130
|
+
function App() {
|
|
131
|
+
return (
|
|
132
|
+
<>
|
|
133
|
+
{/* Show a separate loading UI for the LeftHandColumn */}
|
|
134
|
+
<Suspense fallback={<LeftColumnPlaceholder />}>
|
|
135
|
+
<LeftColumn />
|
|
136
|
+
</Suspense>
|
|
137
|
+
|
|
138
|
+
{/* Show a separate loading UI for both the Main and Secondary content */}
|
|
139
|
+
<Suspense fallback={<LoadingGlimmer />}>
|
|
140
|
+
<MainContent />
|
|
141
|
+
<SecondaryContent />
|
|
142
|
+
</Suspense>
|
|
143
|
+
</>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
// @fb-only
|
|
149
|
+
|
|
150
|
+
* In this case, we're showing 2 separate loading UIs:
|
|
151
|
+
* One to be shown until the `LeftColumn` becomes ready
|
|
152
|
+
* And one to be shown until both the `MainContent` and `SecondaryContent` become ready.
|
|
153
|
+
* What is powerful about this is that by more granularly wrapping our components in Suspense, *we allow other components to be rendered earlier as they become ready*. In our example, by separately wrapping `MainContent` and `SecondaryContent` under `Suspense`, we're allowing `LeftColumn` to render as soon as it becomes ready, which might be earlier than when the content sections become ready.
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
## Transitions and Updates that Suspend
|
|
157
|
+
|
|
158
|
+
<FbInternalOnly>
|
|
159
|
+
// @fb-only
|
|
160
|
+
</FbInternalOnly>
|
|
161
|
+
|
|
162
|
+
<OssOnly>
|
|
163
|
+
|
|
164
|
+
`Suspense` boundary fallbacks allow us to describe our loading placeholders when initially rendering some content, but our applications will also have transitions between different content. Specifically, when switching between two components within an already mounted boundary, the new component you're switching to might not have loaded all of its async dependencies, which means that it might also suspend.
|
|
165
|
+
|
|
166
|
+
In these cases, we would still show the `Suspense` boundary fallbacks. However, this means that we would hide existing content in favor of showing the `Suspense` fallback. In future versions of React when concurrent rendering is supported, React will provide an option to support this case and avoid hiding already rendered content with a Suspense fallback when suspending.
|
|
167
|
+
|
|
168
|
+
</OssOnly>
|
|
169
|
+
|
|
170
|
+
## How We Use Suspense in Relay
|
|
171
|
+
|
|
172
|
+
### Queries
|
|
173
|
+
|
|
174
|
+
In our case, our query components are components that can suspend, so we use Suspense to render loading states while a query is being fetched. Let's see what that looks like in practice:
|
|
175
|
+
|
|
176
|
+
Say we have the following query renderer component:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
/**
|
|
180
|
+
* MainContent.react.js
|
|
181
|
+
*
|
|
182
|
+
* Query Component
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
const React = require('React');
|
|
186
|
+
const {graphql, usePreloadedQuery} = require('react-relay');
|
|
187
|
+
|
|
188
|
+
function MainContent(props) {
|
|
189
|
+
// Fetch and render a query
|
|
190
|
+
const data = usePreloadedQuery(
|
|
191
|
+
graphql`...`,
|
|
192
|
+
props.queryRef,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
return (...);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
/**
|
|
201
|
+
* App.react.js
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
const React = require('React');
|
|
205
|
+
const {Suspense} = require('React');
|
|
206
|
+
|
|
207
|
+
function App() {
|
|
208
|
+
return (
|
|
209
|
+
// LoadingGlimmer is rendered via the Suspense fallback
|
|
210
|
+
<Suspense fallback={<LoadingGlimmer />}>
|
|
211
|
+
<MainContent /> {/* MainContent may suspend */}
|
|
212
|
+
</Suspense>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
// @fb-only
|
|
218
|
+
|
|
219
|
+
Let's distill what's going on here:
|
|
220
|
+
|
|
221
|
+
* We have a `MainContent` component, which is a query renderer that fetches and renders a query. `MainContent` will *suspend* rendering when it attempts to fetch the query, indicating that it isn't ready to be rendered yet, and it will resolve when the query is fetched.
|
|
222
|
+
* The `Suspense `component that wraps `MainContent` will detect that `MainContent` suspended, and will render the `fallback` element (i.e. the `LoadingGlimmer` in this case) up until `MainContent` is ready to be rendered; that is, up until the query is fetched.
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
### Fragments
|
|
226
|
+
|
|
227
|
+
<FbInternalOnly>
|
|
228
|
+
// @fb-only
|
|
229
|
+
</FbInternalOnly>
|
|
230
|
+
|
|
231
|
+
<OssOnly>
|
|
232
|
+
|
|
233
|
+
Fragments are also integrated with Suspense in order to support rendering of data that's being `@defer'`d or data that's partially available in the Relay Store (i.e. [partial rendering](../../reusing-cached-data/rendering-partially-cached-data/)).
|
|
234
|
+
|
|
235
|
+
</OssOnly>
|
|
236
|
+
|
|
237
|
+
### Transitions
|
|
238
|
+
|
|
239
|
+
<FbInternalOnly>
|
|
240
|
+
// @fb-only
|
|
241
|
+
</FbInternalOnly>
|
|
242
|
+
|
|
243
|
+
Additionally, our APIs for fetching, [refreshing](../refetching/refreshing-queries.mdx) and [refetching](../refetching/refetching-queries-with-different-data.mdx) and for [rendering connections](../list-data/connections.mdx) are also integrated with Suspense; for these use cases, these APIs will also suspend.
|
|
244
|
+
|
|
245
|
+
<DocsRating />
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: queries
|
|
3
|
+
title: Queries
|
|
4
|
+
slug: /guided-tour/rendering/queries/
|
|
5
|
+
description: Relay guide to queries
|
|
6
|
+
keywords:
|
|
7
|
+
- query
|
|
8
|
+
- usePreloadedQuery
|
|
9
|
+
- useLazyLoadQuery
|
|
10
|
+
- useQueryLoader
|
|
11
|
+
- loadQuery
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
import DocsRating from '@site/src/core/DocsRating';
|
|
15
|
+
import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
|
|
16
|
+
|
|
17
|
+
// @fb-only
|
|
18
|
+
|
|
19
|
+
A [GraphQL Query](https://graphql.org/learn/queries/) is a description of data you want to query from a GraphQL server. It consists of a set of fields (and potentially [fragments](../fragments/)) that we want to request from the GraphQL server. What we can query for will depend on the [GraphQL Schema](https://graphql.org/learn/schema/) exposed on the server, which describes the data that is available for querying.
|
|
20
|
+
|
|
21
|
+
A query can be sent as a request over the network, along with an optional collection of [variables](../variables/) that the query uses, in order to fetch the data. The server response will be a JSON object that matches the shape of the query we sent:
|
|
22
|
+
|
|
23
|
+
```graphql
|
|
24
|
+
query UserQuery($id: ID!) {
|
|
25
|
+
user(id: $id) {
|
|
26
|
+
id
|
|
27
|
+
name
|
|
28
|
+
...UserFragment
|
|
29
|
+
}
|
|
30
|
+
viewer {
|
|
31
|
+
actor {
|
|
32
|
+
name
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fragment UserFragment on User {
|
|
38
|
+
username
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
<FbInternalOnly>
|
|
43
|
+
|
|
44
|
+
[Sample response](https://fburl.com/graphiql/v5hs717f):
|
|
45
|
+
|
|
46
|
+
</FbInternalOnly>
|
|
47
|
+
|
|
48
|
+
<OssOnly>
|
|
49
|
+
|
|
50
|
+
Sample response:
|
|
51
|
+
|
|
52
|
+
</OssOnly>
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"data": {
|
|
57
|
+
"user": {
|
|
58
|
+
"id": "4",
|
|
59
|
+
"name": "Mark Zuckerberg",
|
|
60
|
+
"username": "zuck"
|
|
61
|
+
},
|
|
62
|
+
"viewer": {
|
|
63
|
+
"actor": {
|
|
64
|
+
"name": "Your Name"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## Rendering Queries
|
|
74
|
+
|
|
75
|
+
To *render* a query in Relay, you can use the `usePreloadedQuery` hook. `usePreloadedQuery` takes a query definition and a query reference, and returns the corresponding data for that query and reference.
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
import type {HomeTabQuery} from 'HomeTabQuery.graphql';
|
|
79
|
+
import type {PreloadedQuery} from 'react-relay';
|
|
80
|
+
|
|
81
|
+
const React = require('React');
|
|
82
|
+
const {graphql, usePreloadedQuery} = require('react-relay');
|
|
83
|
+
|
|
84
|
+
type Props = {
|
|
85
|
+
queryRef: PreloadedQuery<HomeTabQuery>,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
function HomeTab(props: Props) {
|
|
89
|
+
const data = usePreloadedQuery(
|
|
90
|
+
graphql`
|
|
91
|
+
query HomeTabQuery($id: ID!) {
|
|
92
|
+
user(id: $id) {
|
|
93
|
+
name
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`,
|
|
97
|
+
props.queryRef,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<h1>{data.user?.name}</h1>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Lets see what's going on here:
|
|
107
|
+
|
|
108
|
+
* `usePreloadedQuery` takes a `graphql` query and a `PreloadedQuery` reference, and returns the data that was fetched for that query.
|
|
109
|
+
* The `PreloadedQuery` (in this case `queryRef`) is an object that describes and references an *instance* of our query that is being (or was) fetched.
|
|
110
|
+
* We'll cover how to actually fetch the query in the next section below, and cover how to show loading states if the query is in-flight when we try to render it in the [Loading States with Suspense](../loading-states/) section.
|
|
111
|
+
* Similarly to [fragments](../fragments/), *the component is automatically subscribed to updates to the query data*: if the data for this query is updated anywhere in the app, the component will automatically re-render with the latest updated data.
|
|
112
|
+
* `usePreloadedQuery` also takes a Flow type parameter, which corresponds to the Flow type for the query, in this case `HomeTabQuery`.
|
|
113
|
+
* The Relay compiler automatically generates Flow types for any declared queries, which are available to import from the generated files with the following name format: *`<query_name>`*`.graphql.js`.
|
|
114
|
+
* Note that the `data` is already properly Flow-typed without requiring an explicit annotation, and is based on the types from the GraphQL schema. For example, the type of `data` above would be: `{ user: ?{ name: ?string } }`.
|
|
115
|
+
* Make sure you're providing a Relay environment using a [Relay Environment Provider](../environment/) at the root of your app before trying to render a query.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
## Fetching Queries for Render
|
|
119
|
+
|
|
120
|
+
Apart from *rendering* a query, we also need to fetch it from the server. Usually we want to fetch queries somewhere at the root of our app, and only have **one or a few queries that [*accumulate*](../fragments/#composing-fragments-into-queries) all the data required to render the screen**. Ideally, we'd fetch them as early as possible, before we even start rendering our app.
|
|
121
|
+
|
|
122
|
+
In order to *fetch* a query for later rendering it, you can use the `useQueryLoader` Hook:
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
import type {HomeTabQuery as HomeTabQueryType} from 'HomeTabQuery.graphql';
|
|
126
|
+
import type {PreloadedQuery} from 'react-relay';
|
|
127
|
+
|
|
128
|
+
const HomeTabQuery = require('HomeTabQuery.graphql')
|
|
129
|
+
const {useQueryLoader} = require('react-relay');
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
type Props = {
|
|
133
|
+
initialQueryRef: PreloadedQuery<HomeTabQueryType>,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
function AppTabs(props) {
|
|
137
|
+
const [
|
|
138
|
+
homeTabQueryRef,
|
|
139
|
+
loadHomeTabQuery,
|
|
140
|
+
] = useQueryLoader(
|
|
141
|
+
HomeTabQuery,
|
|
142
|
+
props.initialQueryRef, /* e.g. provided by router */
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const onSelectHomeTab = () => {
|
|
146
|
+
// Start loading query for HomeTab immediately in the event handler
|
|
147
|
+
// that triggers navigation to that tab, *before* we even start
|
|
148
|
+
// rendering the target tab.
|
|
149
|
+
// Calling this function will update the value of homeTabQueryRef.
|
|
150
|
+
loadHomeTabQuery({id: '4'});
|
|
151
|
+
|
|
152
|
+
// ...
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ...
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
screen === 'HomeTab' && homeTabQueryRef != null ?
|
|
159
|
+
// Pass to component that uses usePreloadedQuery
|
|
160
|
+
<HomeTab queryRef={homeTabQueryRef} /> :
|
|
161
|
+
// ...
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The example above is somewhat contrived, but let's distill what is happening:
|
|
167
|
+
|
|
168
|
+
* We are calling `useQueryLoader` inside our `AppTabs` component.
|
|
169
|
+
* It takes a query, which in this case is our `HomeTabQuery` (the query that we declared in our previous example), and which we can obtain by requiring the auto-generated file: `'HomeTabQuery.graphql'`.
|
|
170
|
+
* It takes an optional initial `PreloadedQuery` to be used as the initial value of the `homeTabQueryRef` that is stored in state and returned by `useQueryLoader`.
|
|
171
|
+
* It also additionally takes a Flow type parameter, which corresponds to the Flow type for the query, in this case `HomeTabQueryType`, which you can also obtain from the auto-generated file: `'HomeTabQuery.graphql'`.
|
|
172
|
+
* Calling `useQueryLoader` allows us to obtain 2 things:
|
|
173
|
+
* `homeTabQueryRef`: A `?PreloadedQuery`, which is an object that describes and references an *instance* of our query that is being (or was) fetched. This value will be null if we haven't fetched the query, i.e. if we haven't called `loadHomeTabQuery`.
|
|
174
|
+
* `loadHomeTabQuery`: A function that will *fetch* the data for this query from the server (if it isn't already cached), and given an object with the [variables](../variables/) the query expects, in this case `{id: '4'}` (we'll go into more detail about how Relay uses cached data in the [Reusing Cached Data For Render](../../reusing-cached-data/) section). Calling this function will also update the value of `homeTabQueryRef` to an instance of a `PreloadedQuery`.
|
|
175
|
+
* Note that the `variables` we pass to this function will be checked by Flow to ensure that you are passing values that match what the GraphQL query expects.
|
|
176
|
+
* Also note that we are calling this function in the event handler that causes the `HomeTab` to be rendered. This allows us to start fetching the data for the screen as early as possible, even before the new tab starts rendering.
|
|
177
|
+
* In fact, `loadQuery` will throw an error if it is called during React's render phase!
|
|
178
|
+
* Note that `useQueryLoader` will automatically dispose of all queries that have been loaded when the component unmounts. Disposing of a query means that Relay will no longer hold on to the data for that particular instance of the query in its cache (we'll cover the lifetime of query data in [Reusing Cached Data For Render](../../reusing-cached-data/) section). Additionally, if the request for the query is still in flight when disposal occurs, it will be canceled.
|
|
179
|
+
* Our `AppTabs` component renders the `HomeTab` component from the previous example, and passes it the corresponding query reference. Note that this parent component owns the lifetime of the data for that query, meaning that when it unmounts, it will of dispose of that query, as mentioned above.
|
|
180
|
+
* Finally, make sure you're providing a Relay environment using a [Relay Environment Provider](../environment/) at the root of your app before trying to use `useQueryLoader`.
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
Sometimes, you want to start a fetch outside of the context of a parent component, for example to fetch the data required for the initial load of the application. For these cases, you can use the `loadQuery` API directly, without using `useQueryLoader`:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
import type {HomeTabQuery as HomeTabQueryType} from 'HomeTabQuery.graphql';
|
|
187
|
+
|
|
188
|
+
const HomeTabQuery = require('HomeTabQuery.graphql')
|
|
189
|
+
const {loadQuery} = require('react-relay');
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
const environment = createEnvironment(...);
|
|
193
|
+
|
|
194
|
+
// At some point during app initialization
|
|
195
|
+
const initialQueryRef = loadQuery<HomeTabQueryType>(
|
|
196
|
+
environment,
|
|
197
|
+
HomeTabQuery,
|
|
198
|
+
{id: '4'},
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// ...
|
|
202
|
+
|
|
203
|
+
// E.g. passing the initialQueryRef to the root component
|
|
204
|
+
render(<AppTabs initialQueryRef={initialQueryRef} initialTab={...} />)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
* In this example, we are calling the `loadQuery` function directly to obtain a `PreloadedQuery` instance that we can later pass to a component that uses `usePreloadedQuery`.
|
|
208
|
+
* In this case, we would expect the root `AppTabs` component to manage the lifetime of the query reference, and dispose of it at the appropriate time, if at all.
|
|
209
|
+
* We've left the details of "app initialization" vague in this example, since that will vary from application to application. The important thing to note here is that we should obtain a query reference before we start rendering the root component. In fact, `loadQuery` will throw an error if it is called during React's render phase!
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
### Render as you Fetch
|
|
213
|
+
|
|
214
|
+
The examples above illustrate how to separate fetching the data from rendering it, in order to start the fetch as early as possible (as opposed to waiting until the component is rendered to start the fetch), and allow us to show content to our users a lot sooner. It also helps prevent waterfalling round trips, and gives us more control and predictability over when the fetch occurs, whereas if we fetch during render, it becomes harder to determine when the fetch will (or should) occur. This fits nicely with the [*"render-as-you-fetch"*](https://reactjs.org/docs/concurrent-mode-suspense.html#approach-3-render-as-you-fetch-using-suspense) pattern with [React Suspense](../loading-states/).
|
|
215
|
+
|
|
216
|
+
This is the preferred pattern for fetching data with Relay, and it applies in several circumstances, such as the initial load of an application, during subsequent navigations, or generally when using UI elements which are initially hidden and later revealed upon an interaction (such as menus, popovers, dialogs, etc), and which also require fetching additional data.
|
|
217
|
+
|
|
218
|
+
// @fb-only
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
## Lazily Fetching Queries during Render
|
|
222
|
+
|
|
223
|
+
Another alternative for fetching a query is to lazily fetch the query when the component is rendered. However, as we've mentioned previously, the preferred pattern is to start fetching queries ahead of rendering. If lazy fetching is used without caution, it can trigger nested or waterfalling round trips, and can degrade performance.
|
|
224
|
+
|
|
225
|
+
To fetch a query lazily, you can use the `useLazyLoadQuery` Hook:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
const React = require('React');
|
|
229
|
+
const {graphql, useLazyLoadQuery} = require('react-relay');
|
|
230
|
+
|
|
231
|
+
function App() {
|
|
232
|
+
const data = useLazyLoadQuery(
|
|
233
|
+
graphql`
|
|
234
|
+
query AppQuery($id: ID!) {
|
|
235
|
+
user(id: $id) {
|
|
236
|
+
name
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
`,
|
|
240
|
+
{id: '4'},
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<h1>{data.user?.name}</h1>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
Lets see what's going on here:
|
|
249
|
+
|
|
250
|
+
* `useLazyLoadQuery` takes a graphql query and some variables for that query, and returns the data that was fetched for that query. The variables are an object containing the values for the [variables](../variables/) referenced inside the GraphQL query.
|
|
251
|
+
* Similarly to [fragments](../fragments/), the component is automatically subscribed to updates to the query data: if the data for this query is updated anywhere in the app, the component will automatically re-render with the latest updated data.
|
|
252
|
+
* `useLazyLoadQuery` additionally takes a Flow type parameter, which corresponds to the Flow type for the query, in this case AppQuery.
|
|
253
|
+
* Remember that Relay automatically generates Flow types for any declared queries, which you can import and use with `useLazyLoadQuery`. These types are available in the generated files with the following name format: `<query_name>.graphql.js`.
|
|
254
|
+
* Note that the `variables` will be checked by Flow to ensure that you are passing values that match what the GraphQL query expects.
|
|
255
|
+
* Note that the data is already properly Flow-typed without requiring an explicit annotation, and is based on the types from the GraphQL schema. For example, the type of `data` above would be: `{ user: ?{ name: ?string } }`.
|
|
256
|
+
* By default, when the component renders, Relay will *fetch* the data for this query (if it isn't already cached), and return it as a the result of the `useLazyLoadQuery` call. We'll go into more detail about how to show loading states in the [Loading States with Suspense](../loading-states/) section, and how Relay uses cached data in the [Reusing Cached Data For Rendering](../../reusing-cached-data/) section.
|
|
257
|
+
* Note that if you re-render your component and pass *different query variables* than the ones originally used, it will cause the query to be fetched again with the new variables, and potentially re-render with different data.
|
|
258
|
+
* Finally, make sure you're providing a Relay environment using a [Relay Environment Provider](../../../api-reference/relay-environment-provider/) at the root of your app before trying to render a query.
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
<DocsRating />
|