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.
Files changed (262) hide show
  1. package/experimental.js +1 -1
  2. package/experimental.js.flow +8 -8
  3. package/handlers/connection/ConnectionHandler.js.flow +5 -5
  4. package/handlers/connection/ConnectionInterface.js.flow +1 -1
  5. package/index.js +1 -1
  6. package/index.js.flow +125 -62
  7. package/lib/experimental.js +3 -3
  8. package/lib/index.js +105 -57
  9. package/lib/multi-actor-environment/ActorIdentifier.js +2 -2
  10. package/lib/multi-actor-environment/MultiActorEnvironment.js +3 -1
  11. package/lib/mutations/commitMutation.js +8 -8
  12. package/lib/mutations/validateMutation.js +4 -4
  13. package/lib/query/GraphQLTag.js +3 -3
  14. package/lib/query/fetchQuery.js +15 -3
  15. package/lib/store/DataChecker.js +38 -4
  16. package/lib/store/NormalizationEngine.js +373 -0
  17. package/lib/store/OperationExecutor.js +172 -113
  18. package/lib/store/RelayConcreteVariables.js +1 -1
  19. package/lib/store/RelayErrorTrie.js +2 -2
  20. package/lib/store/RelayExperimentalGraphResponseTransform.js +8 -8
  21. package/lib/store/RelayModernEnvironment.js +26 -19
  22. package/lib/store/RelayModernRecord.js +18 -8
  23. package/lib/store/RelayModernSelector.js +9 -9
  24. package/lib/store/RelayModernStore.js +152 -43
  25. package/lib/store/RelayPublishQueue.js +1 -1
  26. package/lib/store/RelayReader.js +76 -38
  27. package/lib/store/RelayRecordSource.js +6 -0
  28. package/lib/store/RelayReferenceMarker.js +2 -1
  29. package/lib/store/RelayResponseNormalizer.js +88 -55
  30. package/lib/store/RelayStoreSubscriptions.js +34 -10
  31. package/lib/store/RelayStoreUtils.js +8 -1
  32. package/lib/store/ResolverFragments.js +2 -2
  33. package/lib/store/live-resolvers/LiveResolverCache.js +25 -9
  34. package/lib/store/observeFragmentExperimental.js +17 -1
  35. package/lib/store/observeQueryExperimental.js +2 -2
  36. package/lib/subscription/requestSubscription.js +3 -3
  37. package/lib/util/RelayError.js +3 -0
  38. package/lib/util/RelayFeatureFlags.js +6 -2
  39. package/lib/util/RelayReplaySubject.js +4 -4
  40. package/lib/util/handlePotentialSnapshotErrors.js +2 -2
  41. package/lib/util/stableCopy.js +2 -2
  42. package/llm-docs/api-reference/entrypoint-apis/entrypoint-container.mdx +38 -0
  43. package/llm-docs/api-reference/entrypoint-apis/load-entrypoint.mdx +77 -0
  44. package/llm-docs/api-reference/entrypoint-apis/use-entrypoint-loader.mdx +99 -0
  45. package/llm-docs/api-reference/graphql/graphql-directives.mdx +378 -0
  46. package/llm-docs/api-reference/hooks/_use-lazy-load-query-extra.mdx +16 -0
  47. package/llm-docs/api-reference/hooks/load-query.mdx +84 -0
  48. package/llm-docs/api-reference/hooks/relay-environment-provider.mdx +78 -0
  49. package/llm-docs/api-reference/hooks/use-client-query.mdx +65 -0
  50. package/llm-docs/api-reference/hooks/use-fragment.mdx +69 -0
  51. package/llm-docs/api-reference/hooks/use-lazy-load-query.mdx +62 -0
  52. package/llm-docs/api-reference/hooks/use-mutation.mdx +94 -0
  53. package/llm-docs/api-reference/hooks/use-pagination-fragment.mdx +166 -0
  54. package/llm-docs/api-reference/hooks/use-prefetchable-forward-pagination-fragment.mdx +134 -0
  55. package/llm-docs/api-reference/hooks/use-preloaded-query.mdx +84 -0
  56. package/llm-docs/api-reference/hooks/use-query-loader.mdx +95 -0
  57. package/llm-docs/api-reference/hooks/use-refetchable-fragment.mdx +122 -0
  58. package/llm-docs/api-reference/hooks/use-relay-environment.mdx +37 -0
  59. package/llm-docs/api-reference/hooks/use-subscription.mdx +66 -0
  60. package/llm-docs/api-reference/relay-resolvers/docblock-format.mdx +321 -0
  61. package/llm-docs/api-reference/relay-resolvers/runtime-functions.mdx +94 -0
  62. package/llm-docs/api-reference/relay-runtime/commit-mutation.mdx +65 -0
  63. package/llm-docs/api-reference/relay-runtime/fetch-query.mdx +113 -0
  64. package/llm-docs/api-reference/relay-runtime/field-logger.mdx +170 -0
  65. package/llm-docs/api-reference/relay-runtime/observe-fragment.mdx +92 -0
  66. package/llm-docs/api-reference/relay-runtime/relay-environment.mdx +53 -0
  67. package/llm-docs/api-reference/relay-runtime/request-subscription.mdx +54 -0
  68. package/llm-docs/api-reference/relay-runtime/runtime-configuration.mdx +52 -0
  69. package/llm-docs/api-reference/relay-runtime/store.mdx +734 -0
  70. package/llm-docs/api-reference/relay-runtime/wait-for-fragment-data.mdx +89 -0
  71. package/llm-docs/api-reference/types/CacheConfig.mdx +8 -0
  72. package/llm-docs/api-reference/types/Disposable.mdx +4 -0
  73. package/llm-docs/api-reference/types/GraphQLSubscriptionConfig.mdx +17 -0
  74. package/llm-docs/api-reference/types/MutationConfig.mdx +31 -0
  75. package/llm-docs/api-reference/types/SelectorStoreUpdater.mdx +6 -0
  76. package/llm-docs/api-reference/types/UploadableMap.mdx +3 -0
  77. package/llm-docs/community/learning-resources.mdx +64 -0
  78. package/llm-docs/debugging/declarative-mutation-directives.mdx +34 -0
  79. package/llm-docs/debugging/disallowed-id-types-error.mdx +43 -0
  80. package/llm-docs/debugging/inconsistent-typename-error.mdx +47 -0
  81. package/llm-docs/debugging/relay-devtools.mdx +73 -0
  82. package/llm-docs/debugging/why-null.mdx +116 -0
  83. package/llm-docs/editor-support.mdx +55 -0
  84. package/llm-docs/error-reference/unknown-field.mdx +36 -0
  85. package/llm-docs/getting-started/babel-plugin.mdx +31 -0
  86. package/llm-docs/getting-started/compiler-config.mdx +25 -0
  87. package/llm-docs/getting-started/compiler.mdx +82 -0
  88. package/llm-docs/getting-started/lint-rules.mdx +87 -0
  89. package/llm-docs/getting-started/production.mdx +30 -0
  90. package/llm-docs/getting-started/quick-start.mdx +213 -0
  91. package/llm-docs/glossary/glossary.mdx +1040 -0
  92. package/llm-docs/guided-tour/list-data/advanced-pagination.mdx +157 -0
  93. package/llm-docs/guided-tour/list-data/connections.mdx +81 -0
  94. package/llm-docs/guided-tour/list-data/pagination.mdx +193 -0
  95. package/llm-docs/guided-tour/list-data/rendering-connections.mdx +112 -0
  96. package/llm-docs/guided-tour/list-data/streaming-pagination.mdx +87 -0
  97. package/llm-docs/guided-tour/managing-data-outside-react/retaining-queries.mdx +51 -0
  98. package/llm-docs/guided-tour/refetching/refetching-queries-with-different-data.mdx +337 -0
  99. package/llm-docs/guided-tour/refetching/refreshing-queries.mdx +350 -0
  100. package/llm-docs/guided-tour/rendering/environment.mdx +59 -0
  101. package/llm-docs/guided-tour/rendering/error-states.mdx +295 -0
  102. package/llm-docs/guided-tour/rendering/fragments.mdx +354 -0
  103. package/llm-docs/guided-tour/rendering/loading-states.mdx +245 -0
  104. package/llm-docs/guided-tour/rendering/queries.mdx +261 -0
  105. package/llm-docs/guided-tour/rendering/variables.mdx +233 -0
  106. package/llm-docs/guided-tour/reusing-cached-data/fetch-policies.mdx +56 -0
  107. package/llm-docs/guided-tour/reusing-cached-data/filling-in-missing-data.mdx +102 -0
  108. package/llm-docs/guided-tour/reusing-cached-data/introduction.mdx +22 -0
  109. package/llm-docs/guided-tour/reusing-cached-data/presence-of-data.mdx +93 -0
  110. package/llm-docs/guided-tour/reusing-cached-data/rendering-partially-cached-data.mdx +175 -0
  111. package/llm-docs/guided-tour/reusing-cached-data/staleness-of-data.mdx +116 -0
  112. package/llm-docs/guided-tour/updating-data/client-only-data.mdx +115 -0
  113. package/llm-docs/guided-tour/updating-data/graphql-mutations.mdx +334 -0
  114. package/llm-docs/guided-tour/updating-data/graphql-subscriptions.mdx +279 -0
  115. package/llm-docs/guided-tour/updating-data/imperatively-modifying-linked-fields.mdx +511 -0
  116. package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data-legacy.mdx +142 -0
  117. package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data.mdx +275 -0
  118. package/llm-docs/guided-tour/updating-data/introduction.mdx +25 -0
  119. package/llm-docs/guided-tour/updating-data/local-data-updates.mdx +71 -0
  120. package/llm-docs/guided-tour/updating-data/typesafe-updaters-faq.mdx +83 -0
  121. package/llm-docs/guided-tour/updating-data/updating-connections.mdx +592 -0
  122. package/llm-docs/guides/alias-directive.mdx +160 -0
  123. package/llm-docs/guides/catch-directive.mdx +167 -0
  124. package/llm-docs/guides/client-schema-extensions.mdx +208 -0
  125. package/llm-docs/guides/codemods.mdx +66 -0
  126. package/llm-docs/guides/data-driven-dependencies/client-3d.mdx +255 -0
  127. package/llm-docs/guides/data-driven-dependencies/configuration.mdx +127 -0
  128. package/llm-docs/guides/data-driven-dependencies/introduction.mdx +39 -0
  129. package/llm-docs/guides/data-driven-dependencies/server-3d.mdx +664 -0
  130. package/llm-docs/guides/document-comparison.mdx +106 -0
  131. package/llm-docs/guides/graphql-server-specification.mdx +453 -0
  132. package/llm-docs/guides/network-layer.mdx +69 -0
  133. package/llm-docs/guides/persisted-queries.mdx +328 -0
  134. package/llm-docs/guides/relay-resolvers/context.mdx +99 -0
  135. package/llm-docs/guides/relay-resolvers/defining-fields.mdx +151 -0
  136. package/llm-docs/guides/relay-resolvers/defining-types.mdx +164 -0
  137. package/llm-docs/guides/relay-resolvers/deprecated.mdx +27 -0
  138. package/llm-docs/guides/relay-resolvers/derived-fields.mdx +127 -0
  139. package/llm-docs/guides/relay-resolvers/descriptions.mdx +44 -0
  140. package/llm-docs/guides/relay-resolvers/enabling.mdx +41 -0
  141. package/llm-docs/guides/relay-resolvers/errors.mdx +64 -0
  142. package/llm-docs/guides/relay-resolvers/field-arguments.mdx +63 -0
  143. package/llm-docs/guides/relay-resolvers/introduction.mdx +62 -0
  144. package/llm-docs/guides/relay-resolvers/limitations.mdx +30 -0
  145. package/llm-docs/guides/relay-resolvers/live-fields.mdx +164 -0
  146. package/llm-docs/guides/relay-resolvers/return-types.mdx +161 -0
  147. package/llm-docs/guides/relay-resolvers/suspense.mdx +41 -0
  148. package/llm-docs/guides/required-directive.mdx +240 -0
  149. package/llm-docs/guides/semantic-nullability.mdx +93 -0
  150. package/llm-docs/guides/testing-relay-components.mdx +642 -0
  151. package/llm-docs/guides/testing-relay-with-preloaded-queries.mdx +160 -0
  152. package/llm-docs/guides/throw-on-field-error-directive.mdx +58 -0
  153. package/llm-docs/guides/type-emission.mdx +414 -0
  154. package/llm-docs/home.mdx +32 -0
  155. package/llm-docs/principles-and-architecture/architecture-overview.mdx +24 -0
  156. package/llm-docs/principles-and-architecture/compiler-architecture.mdx +106 -0
  157. package/llm-docs/principles-and-architecture/runtime-architecture.mdx +249 -0
  158. package/llm-docs/principles-and-architecture/thinking-in-graphql.mdx +309 -0
  159. package/llm-docs/principles-and-architecture/thinking-in-relay.mdx +104 -0
  160. package/llm-docs/principles-and-architecture/videos.mdx +50 -0
  161. package/llm-docs/tutorial/arrays-lists.mdx +126 -0
  162. package/llm-docs/tutorial/fragments-1.mdx +487 -0
  163. package/llm-docs/tutorial/graphql.mdx +172 -0
  164. package/llm-docs/tutorial/interfaces-polymorphism.mdx +161 -0
  165. package/llm-docs/tutorial/intro.mdx +58 -0
  166. package/llm-docs/tutorial/mutations-updates.mdx +624 -0
  167. package/llm-docs/tutorial/organizing-mutations-queries-and-subscriptions.mdx +13 -0
  168. package/llm-docs/tutorial/queries-1.mdx +267 -0
  169. package/llm-docs/tutorial/queries-2.mdx +389 -0
  170. package/llm-docs/tutorial/refetchable-fragments.mdx +352 -0
  171. package/multi-actor-environment/ActorIdentifier.js.flow +2 -2
  172. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +7 -7
  173. package/multi-actor-environment/ActorUtils.js.flow +1 -1
  174. package/multi-actor-environment/MultiActorEnvironment.js.flow +12 -8
  175. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +3 -3
  176. package/mutations/RelayDeclarativeMutationConfig.js.flow +9 -9
  177. package/mutations/RelayRecordProxy.js.flow +8 -11
  178. package/mutations/RelayRecordSourceMutator.js.flow +4 -4
  179. package/mutations/RelayRecordSourceProxy.js.flow +4 -4
  180. package/mutations/RelayRecordSourceSelectorProxy.js.flow +6 -6
  181. package/mutations/applyOptimisticMutation.js.flow +2 -2
  182. package/mutations/commitMutation.js.flow +20 -16
  183. package/mutations/createUpdatableProxy.js.flow +19 -19
  184. package/mutations/readUpdatableFragment.js.flow +3 -3
  185. package/mutations/readUpdatableQuery.js.flow +3 -3
  186. package/mutations/validateMutation.js.flow +7 -7
  187. package/network/RelayNetworkTypes.js.flow +4 -4
  188. package/network/RelayObservable.js.flow +16 -14
  189. package/network/RelayQueryResponseCache.js.flow +3 -3
  190. package/network/wrapNetworkWithLogObserver.js.flow +1 -1
  191. package/package.json +2 -1
  192. package/query/GraphQLTag.js.flow +22 -10
  193. package/query/fetchQuery.js.flow +23 -10
  194. package/query/fetchQuery_DEPRECATED.js.flow +1 -1
  195. package/store/DataChecker.js.flow +43 -9
  196. package/store/NormalizationEngine.js.flow +779 -0
  197. package/store/OperationExecutor.js.flow +173 -70
  198. package/store/RelayConcreteVariables.js.flow +5 -5
  199. package/store/RelayErrorTrie.js.flow +12 -12
  200. package/store/RelayExperimentalGraphResponseHandler.js.flow +3 -3
  201. package/store/RelayExperimentalGraphResponseTransform.js.flow +10 -10
  202. package/store/RelayModernEnvironment.js.flow +41 -26
  203. package/store/RelayModernFragmentSpecResolver.js.flow +1 -1
  204. package/store/RelayModernOperationDescriptor.js.flow +1 -1
  205. package/store/RelayModernRecord.js.flow +46 -22
  206. package/store/RelayModernSelector.js.flow +21 -21
  207. package/store/RelayModernStore.js.flow +219 -58
  208. package/store/RelayOperationTracker.js.flow +2 -2
  209. package/store/RelayOptimisticRecordSource.js.flow +2 -2
  210. package/store/RelayPublishQueue.js.flow +21 -12
  211. package/store/RelayReader.js.flow +130 -58
  212. package/store/RelayRecordSource.js.flow +10 -0
  213. package/store/RelayRecordState.js.flow +1 -1
  214. package/store/RelayReferenceMarker.js.flow +5 -4
  215. package/store/RelayResponseNormalizer.js.flow +130 -54
  216. package/store/RelayStoreSubscriptions.js.flow +52 -8
  217. package/store/RelayStoreTypes.js.flow +153 -64
  218. package/store/RelayStoreUtils.js.flow +15 -7
  219. package/store/ResolverCache.js.flow +2 -2
  220. package/store/ResolverFragments.js.flow +12 -12
  221. package/store/StoreInspector.js.flow +6 -7
  222. package/store/cloneRelayHandleSourceField.js.flow +1 -1
  223. package/store/cloneRelayScalarHandleSourceField.js.flow +1 -1
  224. package/store/createRelayContext.js.flow +1 -1
  225. package/store/createRelayLoggingContext.js.flow +4 -4
  226. package/store/defaultGetDataID.js.flow +2 -2
  227. package/store/isRelayModernEnvironment.js.flow +4 -2
  228. package/store/live-resolvers/LiveResolverCache.js.flow +55 -20
  229. package/store/live-resolvers/LiveResolverSuspenseSentinel.js.flow +3 -3
  230. package/store/live-resolvers/getOutputTypeRecordIDs.js.flow +1 -1
  231. package/store/live-resolvers/isLiveStateValue.js.flow +2 -2
  232. package/store/live-resolvers/resolverDataInjector.js.flow +8 -5
  233. package/store/observeFragmentExperimental.js.flow +49 -20
  234. package/store/observeQueryExperimental.js.flow +5 -5
  235. package/store/readInlineData.js.flow +4 -4
  236. package/store/waitForFragmentExperimental.js.flow +3 -3
  237. package/subscription/requestSubscription.js.flow +7 -7
  238. package/util/NormalizationNode.js.flow +34 -32
  239. package/util/ReaderNode.js.flow +32 -30
  240. package/util/RelayConcreteNode.js.flow +5 -5
  241. package/util/RelayError.js.flow +4 -1
  242. package/util/RelayFeatureFlags.js.flow +21 -1
  243. package/util/RelayProfiler.js.flow +1 -1
  244. package/util/RelayReplaySubject.js.flow +3 -3
  245. package/util/RelayRuntimeTypes.js.flow +11 -11
  246. package/util/createPayloadFor3DField.js.flow +9 -5
  247. package/util/deepFreeze.js.flow +2 -2
  248. package/util/getFragmentIdentifier.js.flow +1 -1
  249. package/util/getPaginationMetadata.js.flow +1 -1
  250. package/util/getPaginationVariables.js.flow +1 -1
  251. package/util/getPendingOperationsForFragment.js.flow +2 -2
  252. package/util/getRefetchMetadata.js.flow +6 -5
  253. package/util/getValueAtPath.js.flow +3 -3
  254. package/util/handlePotentialSnapshotErrors.js.flow +5 -5
  255. package/util/isEmptyObject.js.flow +1 -1
  256. package/util/isPromise.js.flow +2 -2
  257. package/util/isScalarAndEqual.js.flow +1 -1
  258. package/util/recycleNodesInto.js.flow +2 -2
  259. package/util/registerEnvironmentWithDevTools.js.flow +1 -1
  260. package/util/shallowFreeze.js.flow +1 -1
  261. package/util/stableCopy.js.flow +5 -5
  262. package/util/withProvidedVariables.js.flow +14 -10
@@ -0,0 +1,233 @@
1
+ ---
2
+ id: variables
3
+ title: Variables
4
+ slug: /guided-tour/rendering/variables/
5
+ description: Relay guide to query variables
6
+ keywords:
7
+ - query
8
+ - variables
9
+ ---
10
+
11
+ import DocsRating from '@site/src/core/DocsRating';
12
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
13
+
14
+ You may have noticed that the query declarations in our examples above contain references to an `$id` symbol inside the GraphQL code: these are [GraphQL Variables](https://graphql.org/learn/queries/#variables).
15
+
16
+ GraphQL variables are a construct that allows referencing dynamic values inside a GraphQL query. When fetching a query from the server, we also need to provide as input the actual set of values to use for the variables declared inside the query:
17
+
18
+ ```graphql
19
+ query UserQuery($id: ID!) {
20
+ # The value of $id is used as input to the user() call:
21
+ user(id: $id) {
22
+ id
23
+ name
24
+ }
25
+ }
26
+ ```
27
+
28
+ In the above, `ID!` is the type of the `$id` variable. That is, it is a required ID.
29
+
30
+ When sending a network request to fetch the query above, we need to provide both the query, and the variables to be used for this particular execution of the query. For example:
31
+
32
+ ```graphql
33
+ # Query:
34
+ query UserQuery($id: ID!) {
35
+ # ...
36
+ }
37
+
38
+ # Variables:
39
+ {"id": 4}
40
+ ```
41
+
42
+
43
+ <FbInternalOnly>
44
+
45
+ Fetching the above query and variables from the server would produce the following response, which can also be visualized in [GraphiQL](https://fburl.com/graphiql/kiuar058):
46
+
47
+ </FbInternalOnly>
48
+
49
+ <OssOnly>
50
+
51
+ Fetching the above query and variables from the server would produce the following response:
52
+
53
+ </OssOnly>
54
+
55
+ ```json
56
+ {
57
+ "data": {
58
+ "user": {
59
+ "id": "4",
60
+ "name": "Mark Zuckerberg"
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+
67
+ * * *
68
+
69
+ Fragments can also reference variables that have been declared by a query:
70
+
71
+ ```graphql
72
+ fragment UserFragment on User {
73
+ name
74
+ profile_picture(scale: $scale) {
75
+ uri
76
+ }
77
+ }
78
+
79
+
80
+ query ViewerQuery($scale: Float!) {
81
+ viewer {
82
+ actor {
83
+ ...UserFragment
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ * Even though the fragment above doesn't *declare* the `$scale` variable directly, it can still reference it. Doing so makes it so any query that includes this fragment, either directly or transitively, *must* declare the variable and its type, otherwise an error will be produced.
90
+ * In other words, *query variables are available globally by any fragment that is a descendant of the query*.
91
+ * A fragment which references a global variable can only be included (directly or transitively) in a query which defines that global variable.
92
+
93
+
94
+ In Relay, fragment declarations inside components can also reference query variables:
95
+
96
+ ```js
97
+ function UserComponent(props: Props) {
98
+ const data = useFragment(
99
+ graphql`
100
+ fragment UserComponent_user on User {
101
+ name
102
+ profile_picture(scale: $scale) {
103
+ uri
104
+ }
105
+ }
106
+ `,
107
+ props.user,
108
+ );
109
+
110
+ return (...);
111
+ }
112
+ ```
113
+
114
+ * The above fragment could be included by multiple queries, and rendered by different components, which means that any query that ends up rendering/including the above fragment *must* declare the `$scale` variable.
115
+ * If any query that happens to include this fragment *doesn't* declare the `$scale` variable, an error will be produced by the Relay Compiler at build time, ensuring that an incorrect query never gets sent to the server (sending a query with missing variable declarations will also produce an error in the server).
116
+
117
+
118
+
119
+ ## @arguments and @argumentDefinitions
120
+
121
+ Relay also provides a way to declare variables that are scoped locally to a fragment using the `@arguments` and `@argumentDefinitions` directives. Fragments that use local variables are easy to customize and reuse, since they do not depend on the value of global (query-level) variables.
122
+
123
+ ```js
124
+ /**
125
+ * Declare a fragment that accepts arguments with @argumentDefinitions
126
+ */
127
+
128
+ function TaskView(props) {
129
+ const data = useFragment(
130
+ graphql`
131
+ fragment TaskView_task on Task
132
+ @argumentDefinitions(showDetailedResults: {type: "Boolean!"}) {
133
+ name
134
+ is_completed
135
+ ... @include(if: $showDetailedResults) {
136
+ description
137
+ }
138
+ }
139
+ `,
140
+ props.task,
141
+ );
142
+ }
143
+ ```
144
+
145
+ ```js
146
+ /**
147
+ * Include fragment using @arguments
148
+ */
149
+
150
+ function TaskList(props) {
151
+ const data = usePreloadedQuery(
152
+ graphql`
153
+ query TaskListQuery {
154
+ todays_tasks {
155
+ ...TaskView_task @arguments(showDetailedResults: true)
156
+ }
157
+ tomorrows_tasks {
158
+ ...TaskView_task @arguments(showDetailedResults: false)
159
+ }
160
+ }
161
+ `,
162
+ props.queryRef,
163
+ );
164
+ }
165
+ ```
166
+
167
+ * Locally-scoped variables also make it easier to reuse a fragment from another query.
168
+ * A query definition must list all variables that are used by any nested fragments, including in recursively-nested fragments.
169
+ * Since a fragment can potentially be accessible from many queries, modifying a fragment that uses global variables can require changes to many query definitions.
170
+ * This can also lead to awkward situations, like having multiple versions of the "same" variable, such as `$showDetailedResults` and `$showDetails`.
171
+
172
+ * Since fragments with only locally-scoped variables do not use global variables, they do not suffer from this issue.
173
+
174
+ * Note that when passing `@arguments` to a fragment, we can pass a literal value or pass another variable. The variable can be a global query variable, a local variable declared via `@argumentDefinitions` or a literal (e.g. `42.0`).
175
+ * When we actually fetch `TaskView_task` as part of a query, the `showDetailedResults` value will depend on the argument that was provided by the parent of `TaskView_task`:
176
+
177
+ Fragments that expect arguments can also declare default values, making the arguments optional:
178
+
179
+ ```js
180
+ /**
181
+ * Declare a fragment that accepts arguments with default values
182
+ */
183
+
184
+ function TaskView(props) {
185
+ const data = useFragment(
186
+ graphql`
187
+ fragment TaskView_task on Task
188
+ @argumentDefinitions(showDetailedResults: {type: "Boolean!", defaultValue: true}) {
189
+ name
190
+ is_completed
191
+ ... @include(if: $showDetailedResults) {
192
+ description
193
+ }
194
+ }
195
+ `,
196
+ props.task,
197
+ );
198
+ }
199
+ ```
200
+
201
+ ```js
202
+ function TaskList(props) {
203
+ const data = usePreloadedQuery(
204
+ graphql`
205
+ query TaskListQuery {
206
+ todays_tasks {
207
+ ...TaskView_task
208
+ }
209
+ tomorrows_tasks {
210
+ ...TaskView_task @arguments(showDetailedResults: false)
211
+ }
212
+ }
213
+ `,
214
+ props.queryRef,
215
+ );
216
+ }
217
+ ```
218
+
219
+ * Not passing the argument to `TaskView_task` makes it use the default value for its locally declared `$showDetailedResult` variable.
220
+
221
+
222
+
223
+ ## Accessing GraphQL Variables At Runtime
224
+
225
+
226
+ If you want to access the variables that were set at the query root, the recommended approach is to pass the variables down the component tree in your application, using props, or your own application-specific context.
227
+
228
+ Relay currently does not expose the resolved variables (i.e. after applying argument definitions) for a specific fragment, and you should very rarely need to do so.
229
+
230
+
231
+
232
+
233
+ <DocsRating />
@@ -0,0 +1,56 @@
1
+ ---
2
+ id: fetch-policies
3
+ title: Fetch Policies
4
+ slug: /guided-tour/reusing-cached-data/fetch-policies/
5
+ description: Relay guide to fetch policies
6
+ keywords:
7
+ - fetch policy
8
+ - network-only
9
+ - store-only
10
+ - store-and-network
11
+ - store-or-network
12
+ ---
13
+
14
+ import DocsRating from '@site/src/core/DocsRating';
15
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
16
+
17
+ The first step to reusing locally cached data is to pass a `fetchPolicy` to the `loadQuery` function, which can be provided by `useQueryLoader` (see the [Fetching Queries section](../../rendering/queries/)):
18
+
19
+ ```js
20
+ const React = require('React');
21
+ const {graphql} = require('react-relay');
22
+
23
+ function AppTabs() {
24
+ const [
25
+ queryRef,
26
+ loadQuery,
27
+ ] = useQueryLoader(HomeTabQuery);
28
+
29
+ const onSelectHomeTab = () => {
30
+ loadQuery({id: '4'}, {fetchPolicy: 'store-or-network'});
31
+ }
32
+
33
+ // ...
34
+ }
35
+ ```
36
+
37
+ The provided `fetchPolicy` will determine:
38
+
39
+ * *whether* the query should be fulfilled from the local cache, and
40
+ * *whether* a network request should be made to fetch the query from the server, depending on the availability of the data for that query in the store.
41
+
42
+
43
+ By default, Relay will try to read the query from the local cache; if any piece of data for that query is [missing](../presence-of-data/) or [stale](../staleness-of-data/), it will fetch the entire query from the network. This default `fetchPolicy` is called "*store-or-network".*
44
+
45
+ Specifically, `fetchPolicy` can be any of the following options: **
46
+
47
+ * "store-or-network": *(default)* *will* reuse locally cached data, and will *only* send a network request if any data for the query is [missing](../presence-of-data/) or [stale](../staleness-of-data/). If the query is fully cached, a network request will *not* be made.
48
+ * "store-and-network": *will* reuse locally cached data and will *always* send a network request, regardless of whether any data was [missing](../presence-of-data/) or [stale](../staleness-of-data/) in the store.
49
+ * "network-only": *will* *not* reuse locally cached data, and will *always* send a network request to fetch the query, ignoring any data that might be locally cached and whether it's [missing](../presence-of-data/) or [stale](../staleness-of-data/).
50
+ * "store-only": *will* *only* reuse locally cached data, and will *never* send a network request to fetch the query. In this case, the responsibility of fetching the query falls to the caller, but this policy could also be used to read and operate on data that is entirely [local](../../updating-data/local-data-updates/).
51
+
52
+
53
+ Note that the `refetch` function discussed in the [Refetching Queries](../refetching/refetching-queries-with-different-data.mdx) section also takes a `fetchPolicy`.
54
+
55
+
56
+ <DocsRating />
@@ -0,0 +1,102 @@
1
+ ---
2
+ id: filling-in-missing-data
3
+ title: Filling in Missing Data (Missing Field Handlers)
4
+ slug: /guided-tour/reusing-cached-data/filling-in-missing-data/
5
+ description: Relay guide to filling in missing data
6
+ keywords:
7
+ - missing field handler
8
+ - missing data
9
+ ---
10
+
11
+ import DocsRating from '@site/src/core/DocsRating';
12
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
13
+
14
+ // @fb-only
15
+
16
+ In the previous section we covered how to reuse data that is fully or partially cached, however there are cases in which Relay can't automatically tell that it can reuse some of the data it already has from other queries in order to fulfill a specific query. Specifically, Relay knows how to reuse data that is cached for a query that has been fetched before; that is, if you fetch the exact same query twice, Relay will know that it has the data cached for that query the second time it tries to evaluate it.
17
+
18
+ However, when using different queries, there might still be cases where different queries point to the same data, which we'd want to be able to reuse. For example, imagine the following two queries:
19
+
20
+ ```js
21
+ // Query 1
22
+
23
+ query UserQuery {
24
+ user(id: 4) {
25
+ name
26
+ }
27
+ }
28
+ ```
29
+
30
+ ```js
31
+ // Query 2
32
+
33
+ query NodeQuery {
34
+ node(id: 4) {
35
+ ... on User {
36
+ name
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+
43
+ These two queries are different, but reference the exact same data. Ideally, if one of the queries was already cached in the store, we should be able to reuse that data when rendering the other query. However, Relay doesn't have this knowledge by default, so we need to configure it to encode the knowledge that a `node(id: 4)` *"is the same as"* `user(id: 4)`.
44
+
45
+ To do so, we can provide `missingFieldHandlers` to the `RelayEnvironment` which specifies this knowledge.
46
+
47
+ // @fb-only
48
+
49
+ ```js
50
+ const {ROOT_TYPE, Environment} = require('relay-runtime');
51
+
52
+ const missingFieldHandlers = [
53
+ {
54
+ handle(field, record, argValues): ?string {
55
+ // Make sure to add a handler for the node field
56
+ if (
57
+ record != null &&
58
+ record.getType() === ROOT_TYPE &&
59
+ field.name === 'node' &&
60
+ argValues.hasOwnProperty('id')
61
+ ) {
62
+ return argValues.id
63
+ }
64
+ if (
65
+ record != null &&
66
+ record.getType() === ROOT_TYPE &&
67
+ field.name === 'user' &&
68
+ argValues.hasOwnProperty('id')
69
+ ) {
70
+ // If field is user(id: $id), look up the record by the value of $id
71
+ return argValues.id;
72
+ }
73
+ if (
74
+ record != null &&
75
+ record.getType() === ROOT_TYPE &&
76
+ field.name === 'story' &&
77
+ argValues.hasOwnProperty('story_id')
78
+ ) {
79
+ // If field is story(story_id: $story_id), look up the record by the
80
+ // value of $story_id.
81
+ return argValues.story_id;
82
+ }
83
+ return undefined;
84
+ },
85
+ kind: 'linked',
86
+ },
87
+ ];
88
+
89
+ const environment = new Environment({/*...*/, missingFieldHandlers});
90
+ ```
91
+
92
+ * `missingFieldHandlers` is an array of *handlers*. Each handler must specify a `handle` function, and the kind of missing fields it knows how to handle. The 2 main types of fields that you'd want to handle are:
93
+ * *'scalar'*: This represents a field that contains a scalar value, for example a number or a string.
94
+ * *'linked'*: This represents a field that references another object, i.e. not a scalar.
95
+ * The `handle` function takes the field that is missing, the record that field belongs to, and any arguments that were passed to the field in the current execution of the query.
96
+ * When handling a *'scalar'* field, the handle function should return a scalar value, in order to use as the value for a missing field
97
+ * When handling a *'linked'* field*,* the handle function should return an *ID*, referencing another object in the store that should be use in place of the missing field. **
98
+ * As Relay attempts to fulfill a query from the local cache, whenever it detects any missing data, it will run any of the provided missing field handlers that match the field type before definitively declaring that the data is missing.
99
+
100
+
101
+
102
+ <DocsRating />
@@ -0,0 +1,22 @@
1
+ ---
2
+ id: introduction
3
+ title: Reusing Cached Data
4
+ slug: /guided-tour/reusing-cached-data/
5
+ description: Relay guide to reusing cached data
6
+ keywords:
7
+ - reusing
8
+ - cached
9
+ ---
10
+
11
+ import DocsRating from '@site/src/core/DocsRating';
12
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
13
+
14
+ While an app is in use, Relay will accumulate and cache *(for some time)* the data for the multiple queries that have been fetched throughout usage of our app. Often times, we'll want to be able to reuse and immediately render this data that is locally cached instead of waiting for a network request when fulfilling a query; this is what we'll cover in this section.
15
+
16
+ Some examples of when this might be useful are:
17
+
18
+ * Navigating between tabs in an app, where each app renders a query. If a tab has already been visited, re-visiting the tab should render it instantly, without having to wait for a network request to fetch the data that we've already fetched before.
19
+ * Navigating to a post that was previously rendered on a feed. If the post has already been rendered on a feed, navigating to the post's permalink page should render the post immediately, since all of the data for the post should already be cached.
20
+ * Even if rendering the post in the permalink page requires more data than rendering the post on a feed, we'd still like to reuse and immediately render as much of the post's data that we already have available locally, without blocking render for the entire post if only a small bit of data is missing.
21
+
22
+ <DocsRating />
@@ -0,0 +1,93 @@
1
+ ---
2
+ id: presence-of-data
3
+ title: Presence of Data
4
+ slug: /guided-tour/reusing-cached-data/presence-of-data/
5
+ description: Relay guide to the presence of data
6
+ keywords:
7
+ - presence
8
+ ---
9
+
10
+ import DocsRating from '@site/src/core/DocsRating';
11
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
12
+ // @fb-only
13
+
14
+
15
+ An important thing to keep in mind when attempting to reuse data that is cached in the Relay store is to understand the lifetime of that data; that is, if it is present in the store, and for how long it will be.
16
+
17
+ Data in the Relay store for a given query will generally be present after the query has been fetched for the first time, as long as that query is being rendered on the screen. If we've never fetched data for a specific query, then it will be missing from the store.
18
+
19
+ However, even after we've fetched data for different queries, we can't keep all of the data that we've fetched indefinitely in memory, since over time it would grow to be too large and too stale. In order to mitigate this, Relay runs a process called *Garbage Collection*, in order to delete data that we're no longer using.
20
+
21
+ ## Garbage Collection in Relay
22
+
23
+ Specifically, Relay runs garbage collection on the local in-memory store by deleting any data that is no longer being referenced by any component in the app.
24
+
25
+ However, this can be at odds with reusing cached data; if the data is deleted too soon, before we try to reuse it again later, that will prevent us from reusing that data to render a screen without having to wait on a network request. To address this, this section will cover what you need to do in order to ensure that the data you want to reuse is kept cached for as long as you need it.
26
+
27
+
28
+ :::note
29
+ NOTE: Usually, you shouldn't need to worry about configuring garbage collection and data retention, as this should be configured by the app infrastructure at the RelayEnvironment level; however, we will cover it here for reference.
30
+ :::
31
+
32
+ // @fb-only
33
+
34
+
35
+
36
+ ## Query Retention
37
+
38
+ Retaining a query indicates to Relay that the data for that query and variables shouldn't be deleted (i.e. garbage collected). Multiple callers might retain a single query, and as long as there is at least one caller retaining a query, it won't be deleted from the store.
39
+
40
+ By default, any query components using `useQueryLoader` / `usePreloadedQuery` or our other APIs will retain the query for as long as they are mounted. After they unmount, they will release the query, which means that the query might be deleted at any point in the future after that occurs.
41
+
42
+ If you need to retain a specific query outside of the components lifecycle, you can use the [`retain`](../../accessing-data-without-react/retaining-queries/) operation:
43
+
44
+ ```js
45
+ // Retain query; this will prevent the data for this query and
46
+ // variables from being garbage collected by Relay
47
+ const disposable = environment.retain(queryDescriptor);
48
+
49
+ // Disposing of the disposable will release the data for this query
50
+ // and variables, meaning that it can be deleted at any moment
51
+ // by Relay's garbage collection if it hasn't been retained elsewhere
52
+ disposable.dispose();
53
+ ```
54
+
55
+ * As mentioned, this will allow you to retain the query even after a query component has unmounted, allowing other components, or future instances of the same component, to reuse the retained data.
56
+
57
+
58
+ ## Controlling Relay's Garbage Collection Policy
59
+
60
+ There are currently 2 options you can provide to your Relay Store in to control the behavior of garbage collection:
61
+
62
+ ### GC Scheduler
63
+
64
+ The `gcScheduler` is a function you can provide to the Relay Store which will determine when a GC execution should be scheduled to run:
65
+
66
+ ```js
67
+ // Sample scheduler function
68
+ // Accepts a callback and schedules it to run at some future time.
69
+ function gcScheduler(run: () => void) {
70
+ resolveImmediate(run);
71
+ }
72
+
73
+ const store = new Store(source, {gcScheduler});
74
+ ```
75
+
76
+ * By default, if a `gcScheduler` option is not provided, Relay will schedule garbage collection using the `resolveImmediate` function.
77
+ * You can provide a scheduler function to make GC scheduling less aggressive than the default, for example based on time or [scheduler](https://github.com/facebook/react/tree/main/packages/scheduler) priorities, or any other heuristic. By convention, implementations should not execute the callback immediately.
78
+
79
+
80
+ ### GC Release Buffer Size
81
+
82
+ The Relay Store internally holds a release buffer to keep a specific (configurable) number of queries temporarily retained even *after* they have been released by their original owner (which will happen by default when a component rendering that query unmounts). This makes it possible (and more likely) to be able to reuse data when navigating back to a page, tab or piece of content that has been visited before.
83
+
84
+ In order to configure the size of the release buffer, we can specify the `gcReleaseBufferSize` option to the Relay Store:
85
+
86
+ ```js
87
+ const store = new Store(source, {gcReleaseBufferSize: 10});
88
+ ```
89
+
90
+ * Note that having a buffer size of 0 is equivalent to not having the release buffer, which means that queries will be immediately released and collected.
91
+ * By default, environments have a release buffer size of 10.
92
+
93
+ <DocsRating />
@@ -0,0 +1,175 @@
1
+ ---
2
+ id: rendering-partially-cached-data
3
+ title: Rendering Partially Cached Data
4
+ slug: /guided-tour/reusing-cached-data/rendering-partially-cached-data/
5
+ description: Relay guide to rendering partially cached data
6
+ keywords:
7
+ - partially cached data
8
+ - renderPolicy
9
+ ---
10
+
11
+ import DocsRating from '@site/src/core/DocsRating';
12
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
13
+ // @fb-only
14
+ // @fb-only
15
+
16
+ When rendering cached data in Relay, it is possible to perform partial rendering. We define *"partial rendering"* as the ability to immediately render a query that is partially cached. That is, parts of the query might be missing, but parts of the query might already be cached. In these cases, we want to be able to immediately render the parts of the query that are cached, without waiting on the full query to be fetched.
17
+
18
+ This can be useful in scenarios where we want to render a screen or a page as fast as possible, and we know that some of the data for that page is already cached so we can skip a loading state. For example, take the profile page: it is very likely that the user's name has already been cached at some point during usage of the app, so when visiting a profile page, if the name of the user is cached, we'd like to render immediately, even if the rest of the data for the profile page isn't available yet.
19
+
20
+
21
+ ### Fragments as boundaries for partial rendering
22
+
23
+ To do this, we rely on the ability of fragment components to *suspend* (see the [Loading States with Suspense](../../rendering/loading-states/) section). A fragment component will suspend if any of the data it declared locally is missing during render, and is currently being fetched. Specifically, it will suspend until the data it requires is fetched, that is, until the query to which it belongs (its *parent query*) is fetched.
24
+
25
+ Let's explain what this means with an example. Say we have the following fragment component:
26
+
27
+ ```js
28
+ /**
29
+ * UsernameComponent.react.js
30
+ *
31
+ * Fragment Component
32
+ */
33
+
34
+ import type {UsernameComponent_user$key} from 'UsernameComponent_user.graphql';
35
+
36
+ const React = require('React');
37
+ const {graphql, useFragment} = require('react-relay');
38
+
39
+ type Props = {
40
+ user: UsernameComponent_user$key,
41
+ };
42
+
43
+ function UsernameComponent(props: Props) {
44
+ const user = useFragment(
45
+ graphql`
46
+ fragment UsernameComponent_user on User {
47
+ username
48
+ }
49
+ `,
50
+ props.user,
51
+ );
52
+ return (...);
53
+ }
54
+
55
+ module.exports = UsernameComponent;
56
+ ```
57
+
58
+
59
+ And we have the following query component, which queries for some data, and also includes the fragment above:
60
+
61
+ ```javascript
62
+ /**
63
+ * AppTabs.react.js
64
+ *
65
+ * Query Loader Component
66
+ */
67
+
68
+ // ....
69
+
70
+ const onSelectHomeTab = () => {
71
+ loadHomeTabQuery({id: '4'}, {fetchPolicy: 'store-or-network'});
72
+ }
73
+
74
+ // ...
75
+
76
+ /**
77
+ * HomeTab.react.js
78
+ *
79
+ * Query Component
80
+ */
81
+
82
+ const React = require('React');
83
+ const {graphql, usePreloadedQuery} = require('react-relay');
84
+
85
+ const UsernameComponent = require('./UsernameComponent.react');
86
+
87
+ function HomeTab(props: Props) {
88
+ const data = usePreloadedQuery(
89
+ graphql`
90
+ query HomeTabQuery($id: ID!) {
91
+ user(id: $id) {
92
+ name
93
+ ...UsernameComponent_user
94
+ }
95
+ }
96
+ `,
97
+ props.queryRef,
98
+ );
99
+
100
+ return (
101
+ <>
102
+ <h1>{data.user?.name}</h1>
103
+ <UsernameComponent user={data.user} />
104
+ </>
105
+ );
106
+ }
107
+ ```
108
+
109
+
110
+ Say that when this `HomeTab` component is rendered, we've already previously fetched *(_only_)* the `name` for the `User` with `{id: 4}`, and it is locally cached in the Relay store associated with our current Relay environment.
111
+
112
+ If we attempt to render the query with a `fetchPolicy` that allows reusing locally cached data (`'store-or-network'`, or `'store-and-network'`), the following will occur:
113
+
114
+ * The query will check if any of its locally-required data is missing. In this case, *it isn't*. Specifically, the query is only directly selecting the `name` field, and that field *is* available in the store.
115
+ * Relay considers data to be missing only if it is declared locally and missing. In other words, data that is selected within fragment spreads does not affect whether the outer query or fragment is determined to have missing data.
116
+ * Given that the query doesn't have any data missing, it will render, and then attempt to render the child `UsernameComponent`.
117
+ * When the `UsernameComponent` attempts to render the `UsernameComponent_user` fragment, Relay will notice that some of the data required to render is missing; specifically, the `username` is missing. At this point, since `UsernameComponent` has missing data, it will suspend rendering until the network request completes. Note that regardless of which `fetchPolicy` you choose, a network request will always be started if any piece of data for the full query, i.e. including fragments, is missing.
118
+
119
+
120
+ At this point, when `UsernameComponent` suspends due to the missing `username`, ideally we should still be able to render the `User`'s `name` immediately, since it's locally cached. However, since we aren't using a `Suspense` component to catch the fragment's suspension, the suspension will bubble up and the entire `App` component will be suspended.
121
+
122
+ In order to achieve the desired effect of rendering the `name` when it's available even if the `username` is missing, we just need to wrap the `UsernameComponent` in `Suspense,` to *allow* the other parts of `App` to continue rendering:
123
+
124
+ ```js
125
+ /**
126
+ * HomeTab.react.js
127
+ *
128
+ * Query Component
129
+ */
130
+
131
+ const React = require('React');
132
+ const {Suspense} = require('React');
133
+ const {graphql, usePreloadedQuery} = require('react-relay');
134
+
135
+ const UsernameComponent = require('./UsernameComponent.react');
136
+
137
+
138
+ function HomeTab() {
139
+ const data = usePreloadedQuery(
140
+ graphql`
141
+ query AppQuery($id: ID!) {
142
+ user(id: $id) {
143
+ name
144
+ ...UsernameComponent_user
145
+ }
146
+ }
147
+ `,
148
+ props.queryRef,
149
+ );
150
+
151
+ return (
152
+ <>
153
+ <h1>{data.user?.name}</h1>
154
+
155
+ {/*
156
+ Wrap the UserComponent in Suspense to allow other parts of the
157
+ App to be rendered even if the username is missing.
158
+ */}
159
+ <Suspense fallback={<LoadingSpinner label="Fetching username" />}>
160
+ <UsernameComponent user={data.user} />
161
+ </Suspense>
162
+ </>
163
+ );
164
+ }
165
+ ```
166
+
167
+ // @fb-only
168
+
169
+ The process that we described above works the same way for nested fragments (i.e. fragments included within other fragments). This means that if the data required to render a fragment is locally cached, the fragment component will be able to render, regardless of whether data for any of its child or descendant fragments is missing. If data for a child fragment is missing, we can wrap it in a `Suspense` component to allow other fragments and parts of the app to continue rendering.
170
+
171
+ As mentioned in our motivating example, this is desirable because it can allows us to skip loading states entirely. More specifically, the ability to render data that is partially available allows us to render intermediate UI states that more closely resemble the final rendered state.
172
+
173
+ // @fb-only
174
+
175
+ <DocsRating />