relay-runtime 20.1.1 → 21.0.1

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 (334) hide show
  1. package/experimental.d.ts +34 -0
  2. package/experimental.js +1 -1
  3. package/experimental.js.flow +11 -11
  4. package/handlers/RelayDefaultHandlerProvider.d.ts +12 -0
  5. package/handlers/connection/ConnectionHandler.d.ts +51 -0
  6. package/handlers/connection/ConnectionHandler.js.flow +5 -5
  7. package/handlers/connection/ConnectionInterface.d.ts +40 -0
  8. package/handlers/connection/ConnectionInterface.js.flow +1 -1
  9. package/handlers/connection/MutationHandlers.d.ts +17 -0
  10. package/index.d.ts +274 -0
  11. package/index.js +1 -1
  12. package/index.js.flow +125 -62
  13. package/lib/experimental.js +3 -3
  14. package/lib/index.js +105 -57
  15. package/lib/multi-actor-environment/ActorIdentifier.js +2 -2
  16. package/lib/multi-actor-environment/MultiActorEnvironment.js +3 -1
  17. package/lib/mutations/commitMutation.js +8 -8
  18. package/lib/mutations/validateMutation.js +4 -4
  19. package/lib/query/GraphQLTag.js +3 -3
  20. package/lib/query/fetchQuery.js +15 -3
  21. package/lib/store/DataChecker.js +38 -4
  22. package/lib/store/NormalizationEngine.js +373 -0
  23. package/lib/store/OperationExecutor.js +172 -113
  24. package/lib/store/RelayConcreteVariables.js +1 -1
  25. package/lib/store/RelayErrorTrie.js +2 -2
  26. package/lib/store/RelayExperimentalGraphResponseTransform.js +8 -8
  27. package/lib/store/RelayModernEnvironment.js +26 -19
  28. package/lib/store/RelayModernRecord.js +18 -8
  29. package/lib/store/RelayModernSelector.js +9 -9
  30. package/lib/store/RelayModernStore.js +152 -43
  31. package/lib/store/RelayPublishQueue.js +1 -1
  32. package/lib/store/RelayReader.js +76 -38
  33. package/lib/store/RelayRecordSource.js +6 -0
  34. package/lib/store/RelayReferenceMarker.js +2 -1
  35. package/lib/store/RelayResponseNormalizer.js +88 -55
  36. package/lib/store/RelayStoreSubscriptions.js +34 -10
  37. package/lib/store/RelayStoreUtils.js +8 -1
  38. package/lib/store/ResolverFragments.js +2 -2
  39. package/lib/store/live-resolvers/LiveResolverCache.js +25 -9
  40. package/lib/store/observeFragmentExperimental.js +17 -1
  41. package/lib/store/observeQueryExperimental.js +2 -2
  42. package/lib/subscription/requestSubscription.js +3 -3
  43. package/lib/util/RelayError.js +3 -0
  44. package/lib/util/RelayFeatureFlags.js +6 -2
  45. package/lib/util/RelayReplaySubject.js +4 -4
  46. package/lib/util/handlePotentialSnapshotErrors.js +2 -2
  47. package/lib/util/stableCopy.js +2 -2
  48. package/llm-docs/api-reference/entrypoint-apis/entrypoint-container.mdx +38 -0
  49. package/llm-docs/api-reference/entrypoint-apis/load-entrypoint.mdx +77 -0
  50. package/llm-docs/api-reference/entrypoint-apis/use-entrypoint-loader.mdx +99 -0
  51. package/llm-docs/api-reference/graphql/graphql-directives.mdx +378 -0
  52. package/llm-docs/api-reference/hooks/_use-lazy-load-query-extra.mdx +16 -0
  53. package/llm-docs/api-reference/hooks/load-query.mdx +84 -0
  54. package/llm-docs/api-reference/hooks/relay-environment-provider.mdx +78 -0
  55. package/llm-docs/api-reference/hooks/use-client-query.mdx +65 -0
  56. package/llm-docs/api-reference/hooks/use-fragment.mdx +69 -0
  57. package/llm-docs/api-reference/hooks/use-lazy-load-query.mdx +62 -0
  58. package/llm-docs/api-reference/hooks/use-mutation.mdx +94 -0
  59. package/llm-docs/api-reference/hooks/use-pagination-fragment.mdx +166 -0
  60. package/llm-docs/api-reference/hooks/use-prefetchable-forward-pagination-fragment.mdx +134 -0
  61. package/llm-docs/api-reference/hooks/use-preloaded-query.mdx +84 -0
  62. package/llm-docs/api-reference/hooks/use-query-loader.mdx +95 -0
  63. package/llm-docs/api-reference/hooks/use-refetchable-fragment.mdx +122 -0
  64. package/llm-docs/api-reference/hooks/use-relay-environment.mdx +37 -0
  65. package/llm-docs/api-reference/hooks/use-subscription.mdx +66 -0
  66. package/llm-docs/api-reference/relay-resolvers/docblock-format.mdx +321 -0
  67. package/llm-docs/api-reference/relay-resolvers/runtime-functions.mdx +94 -0
  68. package/llm-docs/api-reference/relay-runtime/commit-mutation.mdx +65 -0
  69. package/llm-docs/api-reference/relay-runtime/fetch-query.mdx +118 -0
  70. package/llm-docs/api-reference/relay-runtime/field-logger.mdx +170 -0
  71. package/llm-docs/api-reference/relay-runtime/observe-fragment.mdx +92 -0
  72. package/llm-docs/api-reference/relay-runtime/relay-environment.mdx +53 -0
  73. package/llm-docs/api-reference/relay-runtime/request-subscription.mdx +54 -0
  74. package/llm-docs/api-reference/relay-runtime/runtime-configuration.mdx +52 -0
  75. package/llm-docs/api-reference/relay-runtime/store.mdx +734 -0
  76. package/llm-docs/api-reference/relay-runtime/wait-for-fragment-data.mdx +89 -0
  77. package/llm-docs/api-reference/types/CacheConfig.mdx +8 -0
  78. package/llm-docs/api-reference/types/Disposable.mdx +4 -0
  79. package/llm-docs/api-reference/types/GraphQLSubscriptionConfig.mdx +17 -0
  80. package/llm-docs/api-reference/types/MutationConfig.mdx +31 -0
  81. package/llm-docs/api-reference/types/SelectorStoreUpdater.mdx +6 -0
  82. package/llm-docs/api-reference/types/UploadableMap.mdx +3 -0
  83. package/llm-docs/community/learning-resources.mdx +64 -0
  84. package/llm-docs/debugging/declarative-mutation-directives.mdx +34 -0
  85. package/llm-docs/debugging/disallowed-id-types-error.mdx +43 -0
  86. package/llm-docs/debugging/inconsistent-typename-error.mdx +47 -0
  87. package/llm-docs/debugging/relay-devtools.mdx +73 -0
  88. package/llm-docs/debugging/why-null.mdx +116 -0
  89. package/llm-docs/editor-support.mdx +55 -0
  90. package/llm-docs/error-reference/unknown-field.mdx +36 -0
  91. package/llm-docs/getting-started/babel-plugin.mdx +31 -0
  92. package/llm-docs/getting-started/compiler-config.mdx +25 -0
  93. package/llm-docs/getting-started/compiler.mdx +98 -0
  94. package/llm-docs/getting-started/lint-rules.mdx +87 -0
  95. package/llm-docs/getting-started/production.mdx +30 -0
  96. package/llm-docs/getting-started/quick-start.mdx +216 -0
  97. package/llm-docs/glossary/glossary.mdx +1040 -0
  98. package/llm-docs/guided-tour/list-data/advanced-pagination.mdx +157 -0
  99. package/llm-docs/guided-tour/list-data/connections.mdx +81 -0
  100. package/llm-docs/guided-tour/list-data/pagination.mdx +193 -0
  101. package/llm-docs/guided-tour/list-data/rendering-connections.mdx +112 -0
  102. package/llm-docs/guided-tour/list-data/streaming-pagination.mdx +87 -0
  103. package/llm-docs/guided-tour/managing-data-outside-react/retaining-queries.mdx +51 -0
  104. package/llm-docs/guided-tour/refetching/refetching-queries-with-different-data.mdx +337 -0
  105. package/llm-docs/guided-tour/refetching/refreshing-queries.mdx +350 -0
  106. package/llm-docs/guided-tour/rendering/environment.mdx +59 -0
  107. package/llm-docs/guided-tour/rendering/error-states.mdx +295 -0
  108. package/llm-docs/guided-tour/rendering/fragments.mdx +354 -0
  109. package/llm-docs/guided-tour/rendering/loading-states.mdx +245 -0
  110. package/llm-docs/guided-tour/rendering/queries.mdx +261 -0
  111. package/llm-docs/guided-tour/rendering/variables.mdx +233 -0
  112. package/llm-docs/guided-tour/reusing-cached-data/fetch-policies.mdx +56 -0
  113. package/llm-docs/guided-tour/reusing-cached-data/filling-in-missing-data.mdx +102 -0
  114. package/llm-docs/guided-tour/reusing-cached-data/introduction.mdx +22 -0
  115. package/llm-docs/guided-tour/reusing-cached-data/presence-of-data.mdx +93 -0
  116. package/llm-docs/guided-tour/reusing-cached-data/rendering-partially-cached-data.mdx +175 -0
  117. package/llm-docs/guided-tour/reusing-cached-data/staleness-of-data.mdx +116 -0
  118. package/llm-docs/guided-tour/updating-data/client-only-data.mdx +115 -0
  119. package/llm-docs/guided-tour/updating-data/graphql-mutations.mdx +334 -0
  120. package/llm-docs/guided-tour/updating-data/graphql-subscriptions.mdx +279 -0
  121. package/llm-docs/guided-tour/updating-data/imperatively-modifying-linked-fields.mdx +511 -0
  122. package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data-legacy.mdx +142 -0
  123. package/llm-docs/guided-tour/updating-data/imperatively-modifying-store-data.mdx +275 -0
  124. package/llm-docs/guided-tour/updating-data/introduction.mdx +25 -0
  125. package/llm-docs/guided-tour/updating-data/local-data-updates.mdx +71 -0
  126. package/llm-docs/guided-tour/updating-data/typesafe-updaters-faq.mdx +83 -0
  127. package/llm-docs/guided-tour/updating-data/updating-connections.mdx +592 -0
  128. package/llm-docs/guides/alias-directive.mdx +160 -0
  129. package/llm-docs/guides/catch-directive.mdx +167 -0
  130. package/llm-docs/guides/client-schema-extensions.mdx +208 -0
  131. package/llm-docs/guides/codemods.mdx +79 -0
  132. package/llm-docs/guides/data-driven-dependencies/client-3d.mdx +255 -0
  133. package/llm-docs/guides/data-driven-dependencies/configuration.mdx +127 -0
  134. package/llm-docs/guides/data-driven-dependencies/introduction.mdx +39 -0
  135. package/llm-docs/guides/data-driven-dependencies/server-3d.mdx +664 -0
  136. package/llm-docs/guides/document-comparison.mdx +106 -0
  137. package/llm-docs/guides/graphql-server-specification.mdx +453 -0
  138. package/llm-docs/guides/network-layer.mdx +69 -0
  139. package/llm-docs/guides/persisted-queries.mdx +328 -0
  140. package/llm-docs/guides/relay-resolvers/context.mdx +99 -0
  141. package/llm-docs/guides/relay-resolvers/defining-fields.mdx +151 -0
  142. package/llm-docs/guides/relay-resolvers/defining-types.mdx +164 -0
  143. package/llm-docs/guides/relay-resolvers/deprecated.mdx +27 -0
  144. package/llm-docs/guides/relay-resolvers/derived-fields.mdx +127 -0
  145. package/llm-docs/guides/relay-resolvers/descriptions.mdx +44 -0
  146. package/llm-docs/guides/relay-resolvers/enabling.mdx +41 -0
  147. package/llm-docs/guides/relay-resolvers/errors.mdx +64 -0
  148. package/llm-docs/guides/relay-resolvers/field-arguments.mdx +63 -0
  149. package/llm-docs/guides/relay-resolvers/introduction.mdx +62 -0
  150. package/llm-docs/guides/relay-resolvers/limitations.mdx +30 -0
  151. package/llm-docs/guides/relay-resolvers/live-fields.mdx +164 -0
  152. package/llm-docs/guides/relay-resolvers/return-types.mdx +161 -0
  153. package/llm-docs/guides/relay-resolvers/suspense.mdx +41 -0
  154. package/llm-docs/guides/required-directive.mdx +240 -0
  155. package/llm-docs/guides/semantic-nullability.mdx +93 -0
  156. package/llm-docs/guides/testing-relay-components.mdx +642 -0
  157. package/llm-docs/guides/testing-relay-with-preloaded-queries.mdx +160 -0
  158. package/llm-docs/guides/throw-on-field-error-directive.mdx +58 -0
  159. package/llm-docs/guides/type-emission.mdx +414 -0
  160. package/llm-docs/home.mdx +32 -0
  161. package/llm-docs/principles-and-architecture/architecture-overview.mdx +24 -0
  162. package/llm-docs/principles-and-architecture/compiler-architecture.mdx +106 -0
  163. package/llm-docs/principles-and-architecture/runtime-architecture.mdx +249 -0
  164. package/llm-docs/principles-and-architecture/thinking-in-graphql.mdx +309 -0
  165. package/llm-docs/principles-and-architecture/thinking-in-relay.mdx +104 -0
  166. package/llm-docs/principles-and-architecture/videos.mdx +50 -0
  167. package/llm-docs/tutorial/arrays-lists.mdx +126 -0
  168. package/llm-docs/tutorial/fragments-1.mdx +487 -0
  169. package/llm-docs/tutorial/graphql.mdx +172 -0
  170. package/llm-docs/tutorial/interfaces-polymorphism.mdx +161 -0
  171. package/llm-docs/tutorial/intro.mdx +58 -0
  172. package/llm-docs/tutorial/mutations-updates.mdx +624 -0
  173. package/llm-docs/tutorial/organizing-mutations-queries-and-subscriptions.mdx +13 -0
  174. package/llm-docs/tutorial/queries-1.mdx +267 -0
  175. package/llm-docs/tutorial/queries-2.mdx +389 -0
  176. package/llm-docs/tutorial/refetchable-fragments.mdx +352 -0
  177. package/multi-actor-environment/ActorIdentifier.d.ts +17 -0
  178. package/multi-actor-environment/ActorIdentifier.js.flow +2 -2
  179. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +15 -15
  180. package/multi-actor-environment/ActorUtils.js.flow +1 -1
  181. package/multi-actor-environment/MultiActorEnvironment.d.ts +123 -0
  182. package/multi-actor-environment/MultiActorEnvironment.js.flow +32 -24
  183. package/multi-actor-environment/MultiActorEnvironmentTypes.d.ts +225 -0
  184. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +6 -6
  185. package/multi-actor-environment/index.d.ts +14 -0
  186. package/multi-actor-environment.d.ts +8 -0
  187. package/mutations/RelayDeclarativeMutationConfig.d.ts +70 -0
  188. package/mutations/RelayDeclarativeMutationConfig.js.flow +9 -9
  189. package/mutations/RelayRecordProxy.js.flow +8 -11
  190. package/mutations/RelayRecordSourceMutator.js.flow +4 -4
  191. package/mutations/RelayRecordSourceProxy.js.flow +4 -4
  192. package/mutations/RelayRecordSourceSelectorProxy.js.flow +6 -6
  193. package/mutations/applyOptimisticMutation.d.ts +25 -0
  194. package/mutations/applyOptimisticMutation.js.flow +2 -2
  195. package/mutations/commitLocalUpdate.d.ts +10 -0
  196. package/mutations/commitMutation.d.ts +48 -0
  197. package/mutations/commitMutation.js.flow +21 -17
  198. package/mutations/createUpdatableProxy.js.flow +19 -19
  199. package/mutations/readUpdatableFragment.js.flow +3 -3
  200. package/mutations/readUpdatableQuery.js.flow +3 -3
  201. package/mutations/validateMutation.js.flow +7 -7
  202. package/network/RelayNetwork.d.ts +12 -0
  203. package/network/RelayNetworkTypes.d.ts +145 -0
  204. package/network/RelayNetworkTypes.js.flow +18 -18
  205. package/network/RelayObservable.d.ts +197 -0
  206. package/network/RelayObservable.js.flow +32 -30
  207. package/network/RelayQueryResponseCache.d.ts +16 -0
  208. package/network/RelayQueryResponseCache.js.flow +3 -3
  209. package/network/wrapNetworkWithLogObserver.js.flow +1 -1
  210. package/package.json +2 -1
  211. package/query/GraphQLTag.d.ts +45 -0
  212. package/query/GraphQLTag.js.flow +22 -10
  213. package/query/fetchQuery.d.ts +21 -0
  214. package/query/fetchQuery.js.flow +23 -10
  215. package/query/fetchQueryInternal.d.ts +26 -0
  216. package/query/fetchQueryInternal.js.flow +4 -4
  217. package/query/fetchQuery_DEPRECATED.d.ts +17 -0
  218. package/query/fetchQuery_DEPRECATED.js.flow +1 -1
  219. package/store/ClientID.d.ts +14 -0
  220. package/store/DataChecker.js.flow +51 -15
  221. package/store/NormalizationEngine.js.flow +782 -0
  222. package/store/OperationExecutor.d.ts +51 -0
  223. package/store/OperationExecutor.js.flow +204 -98
  224. package/store/RelayConcreteVariables.js.flow +5 -5
  225. package/store/RelayErrorTrie.js.flow +12 -12
  226. package/store/RelayExperimentalGraphResponseHandler.js.flow +3 -3
  227. package/store/RelayExperimentalGraphResponseTransform.js.flow +10 -10
  228. package/store/RelayModernEnvironment.d.ts +97 -0
  229. package/store/RelayModernEnvironment.js.flow +58 -43
  230. package/store/RelayModernFragmentSpecResolver.js.flow +1 -1
  231. package/store/RelayModernOperationDescriptor.d.ts +28 -0
  232. package/store/RelayModernOperationDescriptor.js.flow +1 -1
  233. package/store/RelayModernRecord.d.ts +92 -0
  234. package/store/RelayModernRecord.js.flow +44 -20
  235. package/store/RelayModernSelector.d.ts +123 -0
  236. package/store/RelayModernSelector.js.flow +21 -21
  237. package/store/RelayModernStore.d.ts +57 -0
  238. package/store/RelayModernStore.js.flow +219 -58
  239. package/store/RelayOperationTracker.d.ts +29 -0
  240. package/store/RelayOperationTracker.js.flow +2 -2
  241. package/store/RelayOptimisticRecordSource.js.flow +2 -2
  242. package/store/RelayPublishQueue.js.flow +29 -20
  243. package/store/RelayReader.js.flow +129 -57
  244. package/store/RelayRecordSource.d.ts +26 -0
  245. package/store/RelayRecordSource.js.flow +10 -0
  246. package/store/RelayRecordState.d.ts +28 -0
  247. package/store/RelayRecordState.js.flow +1 -1
  248. package/store/RelayReferenceMarker.js.flow +5 -4
  249. package/store/RelayResponseNormalizer.d.ts +28 -0
  250. package/store/RelayResponseNormalizer.js.flow +130 -62
  251. package/store/RelayStoreSubscriptions.js.flow +52 -8
  252. package/store/RelayStoreTypes.d.ts +1327 -0
  253. package/store/RelayStoreTypes.js.flow +371 -278
  254. package/store/RelayStoreUtils.d.ts +86 -0
  255. package/store/RelayStoreUtils.js.flow +16 -8
  256. package/store/ResolverCache.js.flow +2 -2
  257. package/store/ResolverFragments.d.ts +43 -0
  258. package/store/ResolverFragments.js.flow +22 -14
  259. package/store/StoreInspector.js.flow +7 -8
  260. package/store/ViewerPattern.d.ts +11 -0
  261. package/store/cloneRelayHandleSourceField.js.flow +1 -1
  262. package/store/cloneRelayScalarHandleSourceField.js.flow +1 -1
  263. package/store/createFragmentSpecResolver.d.ts +16 -0
  264. package/store/createRelayContext.js.flow +1 -1
  265. package/store/createRelayLoggingContext.js.flow +4 -4
  266. package/store/defaultGetDataID.js.flow +2 -2
  267. package/store/isRelayModernEnvironment.d.ts +8 -0
  268. package/store/isRelayModernEnvironment.js.flow +4 -2
  269. package/store/live-resolvers/LiveResolverCache.js.flow +55 -20
  270. package/store/live-resolvers/LiveResolverSuspenseSentinel.js.flow +3 -3
  271. package/store/live-resolvers/getOutputTypeRecordIDs.js.flow +1 -1
  272. package/store/live-resolvers/isLiveStateValue.js.flow +2 -2
  273. package/store/live-resolvers/resolverDataInjector.d.ts +27 -0
  274. package/store/live-resolvers/resolverDataInjector.js.flow +8 -5
  275. package/store/observeFragmentExperimental.d.ts +46 -0
  276. package/store/observeFragmentExperimental.js.flow +50 -21
  277. package/store/observeQueryExperimental.d.ts +30 -0
  278. package/store/observeQueryExperimental.js.flow +5 -5
  279. package/store/readInlineData.d.ts +19 -0
  280. package/store/readInlineData.js.flow +5 -5
  281. package/store/waitForFragmentExperimental.d.ts +49 -0
  282. package/store/waitForFragmentExperimental.js.flow +3 -3
  283. package/subscription/requestSubscription.d.ts +27 -0
  284. package/subscription/requestSubscription.js.flow +10 -10
  285. package/util/JSResourceTypes.flow.js.flow +4 -4
  286. package/util/NormalizationNode.d.ts +235 -0
  287. package/util/NormalizationNode.js.flow +127 -123
  288. package/util/ReaderNode.d.ts +264 -0
  289. package/util/ReaderNode.js.flow +156 -151
  290. package/util/RelayConcreteNode.d.ts +120 -0
  291. package/util/RelayConcreteNode.js.flow +32 -32
  292. package/util/RelayError.d.ts +13 -0
  293. package/util/RelayError.js.flow +4 -1
  294. package/util/RelayFeatureFlags.d.ts +40 -0
  295. package/util/RelayFeatureFlags.js.flow +21 -1
  296. package/util/RelayProfiler.d.ts +121 -0
  297. package/util/RelayProfiler.js.flow +1 -1
  298. package/util/RelayReplaySubject.d.ts +25 -0
  299. package/util/RelayReplaySubject.js.flow +3 -3
  300. package/util/RelayRuntimeTypes.d.ts +59 -0
  301. package/util/RelayRuntimeTypes.js.flow +36 -33
  302. package/util/createPayloadFor3DField.d.ts +17 -0
  303. package/util/createPayloadFor3DField.js.flow +9 -5
  304. package/util/deepFreeze.d.ts +8 -0
  305. package/util/deepFreeze.js.flow +2 -2
  306. package/util/getFragmentIdentifier.d.ts +10 -0
  307. package/util/getFragmentIdentifier.js.flow +1 -1
  308. package/util/getPaginationMetadata.d.ts +20 -0
  309. package/util/getPaginationMetadata.js.flow +1 -1
  310. package/util/getPaginationVariables.d.ts +20 -0
  311. package/util/getPaginationVariables.js.flow +1 -1
  312. package/util/getPendingOperationsForFragment.d.ts +18 -0
  313. package/util/getPendingOperationsForFragment.js.flow +2 -2
  314. package/util/getRefetchMetadata.d.ts +19 -0
  315. package/util/getRefetchMetadata.js.flow +6 -5
  316. package/util/getRelayHandleKey.d.ts +8 -0
  317. package/util/getRequestIdentifier.d.ts +17 -0
  318. package/util/getValueAtPath.d.ts +8 -0
  319. package/util/getValueAtPath.js.flow +3 -3
  320. package/util/handlePotentialSnapshotErrors.d.ts +14 -0
  321. package/util/handlePotentialSnapshotErrors.js.flow +5 -5
  322. package/util/isEmptyObject.js.flow +1 -1
  323. package/util/isPromise.d.ts +8 -0
  324. package/util/isPromise.js.flow +2 -2
  325. package/util/isScalarAndEqual.d.ts +8 -0
  326. package/util/isScalarAndEqual.js.flow +1 -1
  327. package/util/recycleNodesInto.d.ts +8 -0
  328. package/util/recycleNodesInto.js.flow +2 -2
  329. package/util/registerEnvironmentWithDevTools.js.flow +1 -1
  330. package/util/shallowFreeze.js.flow +1 -1
  331. package/util/stableCopy.d.ts +8 -0
  332. package/util/stableCopy.js.flow +5 -5
  333. package/util/withProvidedVariables.d.ts +19 -0
  334. package/util/withProvidedVariables.js.flow +14 -10
@@ -0,0 +1,116 @@
1
+ ---
2
+ id: staleness-of-data
3
+ title: Staleness of Data
4
+ slug: /guided-tour/reusing-cached-data/staleness-of-data/
5
+ description: Relay guide to the staleness of data
6
+ keywords:
7
+ - staleness
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
+ Assuming our data is [present in the store](../presence-of-data/), we still need to consider the staleness of such data.
15
+
16
+ By default, Relay will not consider data in the store to be stale (regardless of how long it has been in the cache), unless it's explicitly marked as stale using our data invalidation APIs or if it is older than the query cache expiration time.
17
+
18
+ Marking data as stale is useful for cases when we explicitly know that some data is no longer fresh (for example after executing a [Mutation](../../updating-data/graphql-mutations/)).
19
+
20
+ Relay exposes the following APIs to mark data as stale within an update to the store:
21
+
22
+ ## Globally Invalidating the Relay Store
23
+
24
+ The coarsest type of data invalidation we can perform is invalidating the *whole* store, meaning that all currently cached data will be considered stale after invalidation.
25
+
26
+ To invalidate the store, we can call `invalidateStore()` within an [updater](../../updating-data/graphql-mutations/) function:
27
+
28
+ ```js
29
+ function updater(store) {
30
+ store.invalidateStore();
31
+ }
32
+ ```
33
+
34
+ * Calling `invalidateStore()` will cause *all* data that was written to the store before invalidation occurred to be considered stale, and will require any query to be refetched again the next time it's evaluated.
35
+ * Note that an updater function can be specified as part of a [mutation](../../updating-data/graphql-mutations/), [subscription](../../updating-data/graphql-subscriptions/) or just a [local store update](../../updating-data/local-data-updates/).
36
+
37
+ ## Invalidating Specific Data In The Store
38
+
39
+ We can also be more granular about which data we invalidate and only invalidate *specific records* in the store; compared to global invalidation, only queries that reference the invalidated records will be considered stale after invalidation.
40
+
41
+ To invalidate a record, we can call `invalidateRecord()` within an [updater](../../updating-data/graphql-mutations/) function:
42
+
43
+ ```js
44
+ function updater(store) {
45
+ const user = store.get('<id>');
46
+ if (user != null) {
47
+ user.invalidateRecord();
48
+ }
49
+ }
50
+ ```
51
+
52
+ * Calling `invalidateRecord()` on the `user` record will mark *that* specific user in the store as stale. That means that any query that is cached and references that invalidated user will now be considered stale, and will require to be refetched again the next time it's evaluated.
53
+ * Note that an updater function can be specified as part of a [mutation](../../updating-data/graphql-mutations/), [subscription](../../updating-data/graphql-subscriptions/) or just a [local store update](../../updating-data/local-data-updates/).
54
+
55
+ ## Subscribing to Data Invalidation
56
+
57
+ Just marking the store or records as stale will cause queries to be refetched the next time they are evaluated; so for example, the next time you navigate back to a page that renders a stale query, the query will be refetched even if the data is cached, since the query references stale data.
58
+
59
+ This is useful for a lot of use cases, but there are some times when we'd like to immediately refetch some data upon invalidation, for example:
60
+
61
+ * When invalidating data that is already visible in the current page. Since no navigation is occurring, we won't re-evaluate the queries for the current page, so even if some data is stale, it won't be immediately refetched and we will be showing stale data.
62
+ * When invalidating data that is rendered on a previous view that was never unmounted; since the view wasn't unmounted, if we navigate back, the queries for that view won't be re-evaluated, meaning that even if some is stale, it won't be refetched and we will be showing stale data.
63
+
64
+ // @fb-only
65
+
66
+ To support these use cases, Relay exposes the `useSubscribeToInvalidationState` hook:
67
+
68
+ ```js
69
+ function ProfilePage(props) {
70
+ // Example of querying data for the current page for a given user
71
+ const data = usePreloadedQuery(
72
+ graphql`...`,
73
+ props.preloadedQuery,
74
+ )
75
+
76
+ // Here we subscribe to changes in invalidation state for the given user ID.
77
+ // Whenever the user with that ID is marked as stale, the provided callback will
78
+ // be executed
79
+ useSubscribeToInvalidationState([props.userID], () => {
80
+ // Here we can do things like:
81
+ // - re-evaluate the query by passing a new preloadedQuery to usePreloadedQuery.
82
+ // - imperatively refetch any data
83
+ // - render a loading spinner or gray out the page to indicate that refetch
84
+ // is happening.
85
+ })
86
+
87
+ return (...);
88
+ }
89
+ ```
90
+
91
+ * `useSubscribeToInvalidationState` takes an array of ids, and a callback. Whenever any of the records for those ids are marked as stale, the provided callback will fire.
92
+ * Inside the callback, we can react accordingly and refetch and/or update any current views that are rendering stale data. As an example, we could re-execute the top-level `usePreloadedQuery` by keeping the `preloadedQuery` in state and setting a new one here; since that query is stale at that point, the query will be refetched even if the data is cached in the store.
93
+
94
+
95
+ ## Query Cache Expiration Time
96
+
97
+ In addition, the query cache expiration time affects whether certain operations (i.e. a query and variables) can be fulfilled with data that is already present in the store, i.e. whether the data for a query has become stale.
98
+
99
+ A stale query is one which can be fulfilled with records from the store, and
100
+
101
+ * the time since it was last fetched is greater than the query cache expiration time, or
102
+ * which contains at least one record that was invalidated.
103
+
104
+ This staleness check occurs when a new request is made (e.g. in a call to `loadQuery`). Components which reference stale data will continue to be able to render that data; however, any additional requests which would be fulfilled using stale data will go to the network.
105
+
106
+ In order to configure the query cache expiration time, we can specify the `queryCacheExpirationTime` option to the Relay Store:
107
+
108
+ ```js
109
+ const store = new Store(source, {queryCacheExpirationTime: 5 * 60 * 1000 });
110
+ ```
111
+
112
+ If the query cache expiration time is not provided, staleness checks only look at whether the referenced records have been invalidated.
113
+
114
+
115
+
116
+ <DocsRating />
@@ -0,0 +1,115 @@
1
+ ---
2
+ id: client-only-data
3
+ title: Client-only data
4
+ slug: /guided-tour/updating-data/client-only-data/
5
+ description: Relay guide to client-only data
6
+ keywords:
7
+ - client-only
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
+ ## Client-Only Data (Client Schema Extensions)
15
+
16
+ Relay provides the ability to extend the GraphQL schema *on the client* (i.e. in the browser), via client schema extensions, in order to model data that only needs to be created, read and updated on the client. This can be useful to add small pieces of information to data that is fetched from the server, or to entirely model client-specific state to be stored and managed by Relay.
17
+
18
+ Client schema extensions allows you to modify existing types on the schema (e.g. by adding new fields to a type), or to create entirely new types that only exist in the client.
19
+
20
+
21
+ ### Extending Existing Types
22
+
23
+ <FbInternalOnly>
24
+
25
+ In order to extend an existing type, add a `.graphql` file to the appropriate schema extension directory (depending on the repo):
26
+
27
+ </FbInternalOnly>
28
+
29
+ <OssOnly>
30
+
31
+ In order to extend an existing type, add a `.graphql` file to your appropriate source (`--src`) directory:
32
+
33
+ </OssOnly>
34
+
35
+
36
+ ```graphql
37
+ extend type Comment {
38
+ is_new_comment: Boolean
39
+ }
40
+ ```
41
+
42
+ <FbInternalOnly>
43
+
44
+ // @fb-only
45
+
46
+ </FbInternalOnly>
47
+
48
+ <OssOnly>
49
+
50
+ * In this example, we're using the `extend` keyword to extend an existing type, and we're adding a new field, `is_new_comment` to the existing `Comment` type, which we will be able to [read](#reading-client-only-data) in our components, and [update](#updating-client-only-data) when necessary using normal Relay APIs; you might imagine that we might use this field to render a different visual treatment for a comment if it's new, and we might set it when creating a new comment.
51
+
52
+ </OssOnly>
53
+
54
+ ### Adding New Types
55
+
56
+ You can define types using the same regular GraphQL syntax, by defining it inside a `.graphql` file in `html/js/relay/schema/`:
57
+
58
+
59
+ ```graphql
60
+ # You can define more than one type in a single file
61
+ enum FetchStatus {
62
+ FETCHED
63
+ PENDING
64
+ ERRORED
65
+ }
66
+
67
+
68
+ type FetchState {
69
+ # You can reuse client types to define other types
70
+ status: FetchStatus
71
+
72
+ # You can also reference regular server types
73
+ started_by: User!
74
+ }
75
+
76
+ extend type Item {
77
+ # You can extend server types with client-only types
78
+ fetch_state: FetchState
79
+ }
80
+ ```
81
+
82
+ * In this contrived example, we're defining 2 new client-only types, and `enum` and a regular `type`. Note that they can reference themselves as normal, and reference regular server defined types. Also note that we can extend server types and add fields that are of our client-only types.
83
+ * As mentioned previously, we will be able to [read](#reading-client-only-data) and [update](#updating-client-only-data) this data normally via Relay APIs.
84
+
85
+
86
+
87
+ ### Reading Client-Only Data
88
+
89
+ We can read client-only data be selecting it inside [fragments](../../rendering/fragments/) or [queries](../../rendering/queries/) as normal:
90
+
91
+ ```js
92
+ const data = *useFragment*(
93
+ graphql`
94
+ fragment CommentComponent_comment on Comment {
95
+
96
+ # We can select client-only fields as we would any other field
97
+ is_new_comment
98
+
99
+ body {
100
+ text
101
+ }
102
+ }
103
+ `,
104
+ props.user,
105
+ );
106
+ ```
107
+
108
+
109
+
110
+ ### Updating Client-Only Data
111
+
112
+ In order to update client-only data, you can do so regularly inside [mutation](../graphql-mutations/) or [subscription](../graphql-subscriptions/) updaters, or by using our primitives for doing [local updates](../local-data-updates/) to the store.
113
+
114
+
115
+ <DocsRating />
@@ -0,0 +1,334 @@
1
+ ---
2
+ id: graphql-mutations
3
+ title: GraphQL mutations
4
+ slug: /guided-tour/updating-data/graphql-mutations/
5
+ description: Relay guide to GraphQL mutations
6
+ keywords:
7
+ - mutation
8
+ ---
9
+
10
+ import DocsRating from '@site/src/core/DocsRating';
11
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
12
+
13
+ In GraphQL, data on the server is updated using [GraphQL mutations](https://graphql.org/learn/mutations/) -- analogous to an HTTP POST request. Mutations are read-write server operations, which both modify the data on the backend and allow you to query the modified data in the same request. Note that mutations are opaque to Relay and don't directly update the Relay store, they are high-level requests sent to the server to express a user's intent.
14
+
15
+ ## Writing Mutations
16
+
17
+ A GraphQL mutation looks very similar to a query, except that it uses the `mutation` keyword:
18
+
19
+ ```js
20
+ const StoryLikeButtonLikeMutation = graphql`
21
+ mutation StoreLikeButtonLikeMutation(
22
+ // color1
23
+ $id: ID!
24
+ ) {
25
+ // color2
26
+ likeStory(
27
+ id: $id
28
+ ) {
29
+ // color3
30
+ story {
31
+ likeCount
32
+ }
33
+ }
34
+ }
35
+ `;
36
+ ```
37
+
38
+ * This mutation is named `StoryLikeButton` + `Like` + `Mutation` (note it must begin with the module name and end with the GraphQL operation).
39
+ * A mutation may declare <span className="color1">variables</span> which are passed from the client to the server when the mutation is dispatched. Each variable has a name (`$id`) and a type (`ID!`).
40
+ * The mutation selects a <span className="color2">mutation field</span> defined in the GraphQL schema. Each mutation field that the server defines should correspond to some action that the client can request of the server, such as liking a story. Just like any field, a mutation field can accept arguments to send to the server.
41
+ * The `likeStory` field returns an edge to a node that represents the mutation response. The fields that are available in the mutation response are specified by the GraphQL schema. In this example, we select the `story` field, which is an <span className="color3">edge to the Story that we just liked</span>. From the `story` field, we can query any fields on the Story type, such as the `likeCount`.
42
+
43
+ <FbInternalOnly>
44
+
45
+ :::info
46
+ You can view mutation root fields in the GraphQL Schema Explorer by opening VSCode @ FB and executing the command "Relay: Open GraphQL Schema Explorer". Then, in the "Schema Explorer Tab", click on "Mutation".
47
+
48
+ You can click on the various mutation fields to see their parameters, descriptions and exposed fields.
49
+ :::
50
+
51
+ </FbInternalOnly>
52
+
53
+ A mutation is handled in two separate steps: first, the update is processed on the server, and then the query is executed. This ensures that you only see data that has already been updated as part of your mutation response.
54
+
55
+ <FbInternalOnly>
56
+
57
+ * [It is a best practice](https://fb.workplace.com/groups/644933736023601/?multi_permalinks=823422684841371) to include the `viewer` object and all updated Ents as part of the mutation response.
58
+
59
+ * Check out the [Hack documentation on writing mutations](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) for information on how to add a mutation field to your backend code.
60
+
61
+ </FbInternalOnly>
62
+
63
+ An example of a successful response for the above mutation could look like this:
64
+
65
+ ```json
66
+ {
67
+ "likeStory": {
68
+ "story": {
69
+ "id": "34a8c",
70
+ "likeCount": 47,
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ In the simple case, Relay will automatically update the data in the local store with this new information. In some more complex cases, custom code will be required to tell Relay handle the updates. Read more about this in the [Updaters] section.
77
+
78
+ :::tip[Best Practice]
79
+ In the above example, we select fields individually in the mutation response. Often, these fields will be the same as a fragment related to the mutation (for example, a query for some `StoryLikeButton` component). Rather than have two separate sets of fields that should be kept in sync, it's best practice to spread the component fragment into the mutation response. This way, whenever the fragment changes in your code, the mutation will also return the correct updated data.
80
+
81
+ For example,
82
+ ```
83
+ const StoryLikeButtonLikeMutation = graphql`
84
+ mutation StoryLikeButtonLikeMutation(
85
+ $id: ID,
86
+ ) {
87
+ likeStory(id: $id) {
88
+ story {
89
+ ...StoryLikeButtonFragment
90
+ }
91
+ }
92
+ }
93
+ `;
94
+ ```
95
+
96
+ Spreading fragments is also generally preferable to refetching the data after a mutation has completed, since the updated data can be fetched in a single round trip.
97
+ :::
98
+
99
+ :::info
100
+ **How does Relay know how to update the store?**
101
+ Whenever the response includes an object with an `id` field, Relay will check if the store already contains a record with a matching `ID` in the `id` field of that record. If there is a match, Relay will merge the other fields from the response into the existing record.
102
+ :::
103
+
104
+ ## Using a mutation in Relay
105
+ Mutations in Relay are accessed using the [`useMutation`](../../../api-reference/use-mutation) hook. The hook returns a function to actually send the mutation to the server (e.g. `commitMutation` below), along with a boolean variable to indicate if a mutation is in flight (e.g. `isMutationInFlight`). This is useful for showing pending states like a loading spinner or disabling a "submit" button.
106
+
107
+ For example, using the `StoryLikeButtonLikeMutation` above:
108
+ ```
109
+ const [commitMutation, isMutationInFlight] = useMutation(StoryLikeButtonLikeMutation);
110
+ function onLikeButtonClicked() {
111
+ commitMutation({
112
+ variables: {
113
+ id: data.id,
114
+ },
115
+ })
116
+ }
117
+ const LikeButton = <button onClick={onLikeButtonClicked} disabled={isMutationInFlight}>Like</button>
118
+ ```
119
+
120
+ Note that `commitMutation` takes the variables defined on the mutation in the form of an object.
121
+
122
+ Once that field is executed, the backend will select the updated Feedback object and select `like_count` field off of it. Since the `Story` type contains an `id` field, the Relay compiler will automatically add a selection for the `id` field. When the mutation response is received, Relay will find a feedback object in the store with a matching `id` and update it with the newly received `like_count` value. If this value changes as a result, any components using the value re-rendered.
123
+
124
+ :::note
125
+ If you are using TypeScript or Flow, it's best practice to include a type parameters to the `useMutation` hook:
126
+ ```tsx
127
+ import type {StoryLikeButtonLikeMutation$data, StoryLikeButtonLikeMutation$variables} from 'StoryLikeButtonLikeMutation.graphql';
128
+ const [commitMutation, isMutationInFlight] = useMutation<
129
+ StoryLikeButtonLikeMutationType$variables,
130
+ StoryLikeButtonLikeMutationType$data,
131
+ >(StoryLikeButtonLikeMutation);
132
+ ```
133
+ :::
134
+
135
+ ## Executing a callback when the mutation completes or errors
136
+
137
+ We may want to update some state in response to the mutation succeeding or failing. For example, we might want to alert the user if the mutation failed. The `UseMutationConfig` object passed to `commitMutation` can include the following fields to handle such cases:
138
+
139
+ * `onCompleted`, a callback that is executed when the mutation completes. It is passed the mutation response (stopping at fragment spread boundaries).
140
+ * 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.
141
+ * `onError`, a callback that is executed when the mutation errors. It is passed the error that occurred.
142
+
143
+ ## Declarative mutation directives
144
+
145
+ ### Manipulating connections in response to mutations
146
+
147
+ Relay makes it easy to respond to mutations by adding or removing items from connections (i.e. lists). For example, you might want to append a newly created user to a given connection. For more, see [Using declarative directives](../../list-data/updating-connections/#using-declarative-directives).
148
+
149
+ ### Deleting items in response to mutations
150
+
151
+ In addition, you might want to delete an item from the store in response to a mutation. In order to do this, you would add the `@deleteRecord` directive to the deleted ID. For example:
152
+
153
+ ```graphql
154
+ mutation DeletePostMutation($input: DeletePostData!) {
155
+ delete_post(data: $input) {
156
+ deleted_post {
157
+ id @deleteRecord
158
+ }
159
+ }
160
+ }
161
+ ```
162
+
163
+ ## Imperatively modifying local data
164
+
165
+ At times, the updates you wish to perform are more complex than just updating the values of fields and cannot be handled by the declarative mutation directives. For such situations, the `UseMutationConfig` accepts an `updater` function which gives you full control over how to update the store.
166
+
167
+ This is discussed in more detail in the section on [Imperatively modifying store data](../imperatively-modifying-store-data/).
168
+
169
+ ## Optimistic updates
170
+
171
+ Oftentimes, we don't want to wait for the server to respond before we respond to the user interaction. For example, if a user clicks the "Like" button, we would like to instantly show the affected comment, post, etc. has been liked by the user.
172
+
173
+ More generally, in these cases, we want to immediately update the data in our store optimistically, i.e. under the assumption that the mutation will complete successfully. If the mutation ends up not succeeding, we would like to roll back that optimistic update.
174
+
175
+ ### Optimistic response
176
+
177
+ In order to enable optimistic updates, the `UseMutationConfig` can include an `optimisticResponse` field.
178
+
179
+ For this field to be Flow-typed, the call to `useMutation` must be passed a Flow type parameter **and** the mutation must be decorated with a `@raw_response_type` directive.
180
+
181
+ In the previous example, we might provide the following optimistic response:
182
+
183
+ ```js
184
+ {
185
+ feedback_like: {
186
+ feedback: {
187
+ // Even though the id field is not explicitly selected, the
188
+ // compiler selected it for us
189
+ id: feedbackId,
190
+ viewer_does_like: true,
191
+ },
192
+ },
193
+ }
194
+ ```
195
+
196
+ Now, when we call `commitMutation`, this data will be immediately written into the store. The item in the store with the matching id will be updated with a new value of `viewer_does_like`. Any components which have selected this field will be re-rendered.
197
+
198
+ When the mutation succeeds or errors, the optimistic response will be rolled back.
199
+
200
+ Updating the `like_count` field takes a bit more work. In order to update it, we should also read the **current like count** in the component.
201
+
202
+ ```js
203
+ import type {FeedbackLikeData, LikeButtonMutation} from 'LikeButtonMutation.graphql';
204
+ import type {LikeButton_feedback$fragmentType} from 'LikeButton_feedback.graphql';
205
+
206
+ const {useMutation, graphql} = require('react-relay');
207
+
208
+ function LikeButton({
209
+ feedback: LikeButton_feedback$fragmentType,
210
+ }) {
211
+ const data = useFragment(
212
+ graphql`
213
+ fragment LikeButton_feedback on Feedback {
214
+ __id
215
+ viewer_does_like @required(action: THROW)
216
+ like_count @required(action: THROW)
217
+ }
218
+ `,
219
+ feedback
220
+ );
221
+
222
+ const [commitMutation, isMutationInFlight] = useMutation<LikeButtonMutation>(
223
+ graphql`
224
+ mutation LikeButtonMutation($input: FeedbackLikeData!)
225
+ @raw_response_type {
226
+ feedback_like(data: $input) {
227
+ feedback {
228
+ viewer_does_like
229
+ like_count
230
+ }
231
+ }
232
+ }
233
+ `
234
+ );
235
+
236
+ const changeToLikeCount = data.viewer_does_like ? -1 : 1;
237
+ return <button
238
+ onClick={() => commitMutation({
239
+ variables: {
240
+ input: {id: data.__id},
241
+ },
242
+ optimisticResponse: {
243
+ feedback_like: {
244
+ feedback: {
245
+ id: data.__id,
246
+ viewer_does_like: !data.viewer_does_like,
247
+ like_count: data.like_count + changeToLikeCount,
248
+ },
249
+ },
250
+ },
251
+ })}
252
+ disabled={isMutationInFlight}
253
+ >
254
+ Like
255
+ </button>
256
+ }
257
+ ```
258
+
259
+ :::caution
260
+
261
+ You should be careful, and consider using [optimistic updaters](../imperatively-modifying-store-data/#example) if the value of the optimistic response depends on the value of the store and if there can be multiple optimistic responses affecting that store value.
262
+
263
+ For example, if **two** optimistic responses each increase the like count by one, and the **first** optimistic updater is rolled back, the second optimistic update will still be applied, and the like count in the store will remain increased by two.
264
+
265
+ :::
266
+
267
+ :::caution
268
+
269
+ Optimistic responses contain **many pitfalls!**
270
+
271
+ * An optimistic response can contain the data for the full query response, i.e. including the content of fragment spreads. This means that if a developer selects more fields in components whose fragments are spread in an optimistic response, these components may have inconsistent or partial data during an optimistic update.
272
+ * Because the type of the optimistic update includes the contents of all recursively nested fragments, it can be very large. Adding `@raw_response_type` to certain mutations can degrade the performance of the Relay compiler.
273
+
274
+ :::
275
+
276
+ ### Optimistic updaters
277
+
278
+ Optimistic responses aren't enough for every case. For example, we may want to optimistically update data that we aren't selecting in the mutation. Or, we may want to add or remove items from a connection (and the declarative mutation directives are insufficient for our use case.)
279
+
280
+ For situations like these, the `UseMutationConfig` can contain an `optimisticUpdater` field, which allows developers to imperatively and optimistically update the data in the store. This is discussed in more detail in the section on [Imperatively updating store data](../imperatively-modifying-store-data/).
281
+
282
+ ## Order of execution of updater functions
283
+
284
+ In general, execution of the `updater` and optimistic updates will occur in the following order:
285
+
286
+ * If an `optimisticResponse` is provided, that data will be written into the store.
287
+ * If an `optimisticUpdater` is provided, Relay will execute it and update the store accordingly.
288
+ * If an `optimisticResponse` was provided, the declarative mutation directives present in the mutation will be processed on the optimistic response.
289
+ * If the mutation request succeeds:
290
+ * Any optimistic update that was applied will be rolled back.
291
+ * Relay will write the server response to the store.
292
+ * If an `updater` was provided, Relay will execute it and update the store accordingly. The server payload will be available to the `updater` as a root field in the store.
293
+ * Relay will process any declarative mutation directives using the server response.
294
+ * The `onCompleted` callback will be called.
295
+ * If the mutation request fails:
296
+ * Any optimistic update was applied will be rolled back.
297
+ * The `onError` callback will be called.
298
+
299
+ :::note
300
+ In the case that the store is updated while the mutation is still in flight, Relay will first revert your optimistic update, then apply the new store update before re-applying the optimistic update.
301
+ :::
302
+
303
+ ## Invalidating data during a mutation
304
+
305
+ The recommended approach when executing a mutation is to request *all* the relevant data that was affected by the mutation back from the server (as part of the mutation body), so that our local Relay store is consistent with the state of the server.
306
+
307
+ However, often times it can be unfeasible to know and specify all the possible data that would be affected for mutations that have large rippling effects (e.g. imagine "blocking a user" or "leaving a group").
308
+
309
+ For these types of mutations, it's often more straightforward to explicitly mark some data as stale (or the whole store), so that Relay knows to refetch it the next time it is rendered. In order to do so, you can use the data invalidation APIs documented in our [Staleness of Data section](../../reusing-cached-data/staleness-of-data/).
310
+
311
+ <FbInternalOnly>
312
+
313
+ ## Handling errors
314
+
315
+ GraphQL errors can largely be differentiated as:
316
+
317
+ 1. Operation (query/mutation/subscription) level errors, and
318
+ 2. Field level errors
319
+
320
+ ### Surfacing mutation level errors
321
+
322
+ If you're surfacing an error in the mutation (eg the server rejects the entire mutation because it's invalid), as long as the error returned is considered a [`CRITICAL`](https://www.internalfb.com/code/www/[b5a08782893a]/flib/graphql/experimental/core/error/GraphQL2ErrorSeverity.php?lines=11) error, you can make use of the `onError` callback from `useMutation` to handle that error in whatever way you see fit for your use case.
323
+
324
+ If you control the server resolver, the question you should ask is whether or not throwing a CRITICAL error is the correct behavior for the client. Note though that throwing a CRITICAL error means that Relay will no longer process the interaction, which may not always be what you want if you can still partially update your UI. For example, it's possible that the mutation errored, but still wrote some data to the database, in which case you might still want Relay to process the updated fields.
325
+
326
+ In the non-CRITICAL case the mutation may have failed, but some data was successfully returned in the case of partial data and/or the error response if encoded in the schema. Relay will still process this data, update its store, as well as components relying on that data. That is not true for the case where you've returned a CRITICAL error.
327
+
328
+ ### Surfacing field level errors
329
+ Field level errors from the server are generally recommended to be at the [`ERROR`](https://www.internalfb.com/code/www/[9120ab8aa8a5]/flib/graphql/experimental/core/error/GraphQL2ErrorSeverity.php?lines=17) level, because your UI should still be able to process the other fields that were successfully returned. If you want to explicitly handle the field level error, then we still recommend [modeling that](../../rendering/error-states/#accessing-errors-in-graphql-responses) in your schema.
330
+
331
+ </FbInternalOnly>
332
+
333
+
334
+ <DocsRating />