relay-runtime 20.1.1 → 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 +44 -20
  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 +129 -57
  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 +125 -57
  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,275 @@
1
+ ---
2
+ id: imperatively-modifying-store-data
3
+ title: Imperatively modifying store data
4
+ slug: /guided-tour/updating-data/imperatively-modifying-store-data/
5
+ description: Using readUpdatableQuery to update scalar fields in the store
6
+ keywords:
7
+ - record source
8
+ - store
9
+ - updater
10
+ - typesafe updaters
11
+ - readUpdatableQuery
12
+ - readUpdatableFragment
13
+ - updatable
14
+ ---
15
+
16
+ import DocsRating from '@site/src/core/DocsRating';
17
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
18
+
19
+ :::note
20
+ See also [this guide on updating linked fields in the store](../imperatively-modifying-linked-fields).
21
+ :::
22
+
23
+ Data in Relay stores can be imperatively modified within updater functions.
24
+
25
+ ## When to use updaters
26
+
27
+ ### Complex client updates
28
+
29
+ You might provide an updater function if the changes to local data are more complex than what can be achieved by simply writing a network response to the store and cannot be handled by the declarative mutation directives.
30
+
31
+ ### Client schema extensions
32
+
33
+ In addition, since the network response necessarily will not include data for fields defined in client schema extensions, you may wish to use an updater to initialize data defined in client schema extensions.
34
+
35
+ ### Use of other APIs
36
+
37
+ Lastly, there are things you can only achieve using updaters, such as invalidating nodes, deleting nodes, finding all connections at a given field, etc.
38
+
39
+ ### If multiple optimistic responses modify a given store value
40
+
41
+ If two optimistic responses affect a given value, and the first optimistic response is rolled back, the second one will remain applied.
42
+
43
+ For example, if two optimistic responses each increase a story's like count by one, and the first optimistic response is rolled back, the second optimistic response remains applied. However, it is **not recalculated**, and the value of the like count will remain increased by two.
44
+
45
+ ## When **not** to use updaters
46
+
47
+ ### To trigger other side effects
48
+
49
+ You should use the `onCompleted` callback to trigger other side effects. `onCompleted` callbacks are guaranteed to be called once, but updaters and optimistic updaters can be called repeatedly.
50
+
51
+ ## The various types of updater functions
52
+
53
+ The `useMutation` and `commitMutation` APIs accept configuration objects which can include `optimisticUpdater` and `updater` fields. The `requestSubscription` and `useSubscription` APIs accept configuration objects which can include `updater` fields.
54
+
55
+ In addition, there is another API (`commitLocalUpdate`) which also accepts an updater function. It will be discussed in the [Other APIs for modifying local data](../local-data-updates/) section.
56
+
57
+ ## Optimistic updaters vs updaters
58
+
59
+ Mutations can have both optimistic and regular updaters. Optimistic updaters are executed when a mutation is triggered. When that mutation completes or errors, the optimistic update is rolled back.
60
+
61
+ Regular updaters are executed when a mutation completes successfully.
62
+
63
+ ## Example
64
+
65
+ Let's construct an example in which an `is_new_comment` field (which is defined in a schema extension) is set to `true` on a newly created Feedback object in a mutation updater.
66
+
67
+ ```graphql
68
+ # Feedback.graphql
69
+ extend type Feedback {
70
+ is_new_comment: Boolean
71
+ }
72
+ ```
73
+
74
+ ```js
75
+ // CreateFeedback.js
76
+ import type {Environment} from 'react-relay';
77
+ import type {
78
+ FeedbackCreateData,
79
+ CreateFeedbackMutation,
80
+ CreateFeedbackMutation$data,
81
+ } from 'CreateFeedbackMutation.graphql';
82
+
83
+ const {commitMutation, graphql} = require('react-relay');
84
+ const {ConnectionHandler} = require('relay-runtime');
85
+
86
+ function commitCreateFeedbackMutation(
87
+ environment: Environment,
88
+ input: FeedbackCreateData,
89
+ ) {
90
+ return commitMutation<FeedbackCreateData>(environment, {
91
+ mutation: graphql`
92
+ mutation CreateFeedbackMutation($input: FeedbackCreateData!) {
93
+ feedback_create(input: $input) {
94
+ feedback {
95
+ id
96
+ # Step 1: in the mutation response, spread an updatable fragment (defined below).
97
+ # This updatable fragment will select the fields that we want to update on this
98
+ # particular feedback object.
99
+ ...CreateFeedback_updatable_feedback
100
+ }
101
+ }
102
+ }
103
+ `,
104
+ variables: {input},
105
+
106
+ // Step 2: define an updater
107
+ updater: (store: RecordSourceSelectorProxy, response: ?CreateCommentMutation$data) => {
108
+ // Step 3: Access and nullcheck the feedback object.
109
+ // Note that this could also have been achieved with the @required directive.
110
+ const feedbackRef = response?.feedback_create?.feedback;
111
+ if (feedbackRef == null) {
112
+ return;
113
+ }
114
+
115
+ // Step 3: call store.readUpdatableFragment
116
+ const {updatableData} = store.readUpdatableFragment(
117
+ // Step 4: Pass it a fragment literal, where the fragment contains the @updatable directive.
118
+ // This fragment selects the fields that you wish to update on the feedback object.
119
+ // In step 1, we spread this fragment in the query response.
120
+ graphql`
121
+ fragment CreateFeedback_updatable_feedback on Feedback @updatable {
122
+ is_new_comment
123
+ }
124
+ `,
125
+ // Step 5: Pass the fragment reference.
126
+ feedbackRef
127
+ );
128
+
129
+ // Step 6: Mutate the updatableData object!
130
+ updatableData.is_new_comment = true;
131
+ },
132
+ });
133
+ }
134
+
135
+ module.exports = {commit: commitCreateFeedbackMutation};
136
+ ```
137
+
138
+ Let's distill what's going on here.
139
+
140
+ * The `updater` accepts two parameters: a `RecordSourceSelectorProxy` and an optional object that is the result of reading out the mutation response.
141
+ * The type of this second argument is a nullable version of the `$data` type that is imported from the generated mutation file.
142
+ * The second argument contains just the data selected directly by the mutation argument. In other words, it will not contain any fields selected solely by spread fragments.
143
+ * This `updater` is executed after the mutation response has been written to the store.
144
+ * In this example updater, we do three things:
145
+ * First, we spread an updatable fragment in the mutation response.
146
+ * Second, we read out the fields selected by this fragment by calling `readUpdatableFragment`. This returns an updatable proxy object.
147
+ * Third, we update fields on this updatable proxy.
148
+ * Once this updater completes, the updates that have been recorded are written to the store, and all affected components are re-rendered.
149
+
150
+ ## Example 2: Updating data in response to user interactions
151
+
152
+ Let's consider the common case of updating store data in response to a user interaction. In a click handler, let's a toggle an `is_selected` field. This field is defined on Users in a client schema extension.
153
+
154
+ ```graphql
155
+ # User.graphql
156
+ extend type User {
157
+ is_selected: Boolean
158
+ }
159
+ ```
160
+
161
+ ```js
162
+ // UserSelectToggle.react.js
163
+ import type {RecordSourceSelectorProxy} from 'react-relay';
164
+ import type {UserSelectToggle_viewer$key} from 'UserSelectToggle_viewer.graphql';
165
+
166
+ const {useRelayEnvironment, commitLocalUpdate} = require('react-relay');
167
+
168
+ function UserSelectToggle({ userId, viewerRef }: {
169
+ userId: string,
170
+ viewerRef: UserSelectToggle_viewer$key,
171
+ }) {
172
+ const viewer = useFragment(graphql`
173
+ fragment UserSelectToggle_viewer on Viewer {
174
+ user(user_id: $user_id) {
175
+ id
176
+ name
177
+ is_selected
178
+ ...UserSelectToggle_updatable_user
179
+ }
180
+ }
181
+ `, viewerRef);
182
+
183
+ const environment = useRelayEnvironment();
184
+
185
+ return <button
186
+ onClick={() => {
187
+ commitLocalUpdate(
188
+ environment,
189
+ (store: RecordSourceSelectorProxy) => {
190
+ const userRef = viewer.user;
191
+ if (userRef == null) {
192
+ return;
193
+ }
194
+
195
+ const {updatableData} = store.readUpdatableFragment(
196
+ graphql`
197
+ fragment UserSelectToggle_updatable_user on User @updatable {
198
+ is_selected
199
+ }
200
+ `,
201
+ userRef
202
+ );
203
+
204
+ updatableData.is_selected = !viewer?.user?.is_selected;
205
+ }
206
+ );
207
+ }}
208
+ >
209
+ {viewer?.user?.is_selected ? 'Deselect' : 'Select'} {viewer?.user?.name}
210
+ </button>
211
+ }
212
+ ```
213
+
214
+ Let's distill what's going on here.
215
+
216
+ * In a click handler, we call `commitLocalUpdate`, which accepts a Relay environment and an updater function. **Unlike in the previous examples, this updater does not accept a second parameter** because there is no associated network payload.
217
+ * In this updater function, we access get an updatable proxy object by calling `store.readUpdatableFragment`, and toggle the `is_selected` field.
218
+ * Like the previous example in which we called `readUpdatableFragment`, this can be rewritten to use the `readUpdatableQuery` API.
219
+
220
+ :::note
221
+ This example can be rewritten using the `environment.commitPayload` API, albeit without type safety.
222
+ :::
223
+
224
+ ## Alternative API: `readUpdatableQuery`.
225
+
226
+ In the previous examples, we used an updatable fragment to access the record whose fields we want to update. This can also be possible to do with an updatable query.
227
+
228
+ If we know the path from the root (i.e. the object whose type is `Query`) to the record we wish to modify, we can use the `readUpdatableQuery` API to achieve this.
229
+
230
+ For example, we could set the viewer's `name` field in response to an event as follows:
231
+
232
+ ```js
233
+ // NameUpdater.react.js
234
+ function NameUpdater({ queryRef }: {
235
+ queryRef: NameUpdater_viewer$key,
236
+ }) {
237
+ const environment = useRelayEnvironment();
238
+ const data = useFragment(
239
+ graphql`
240
+ fragment NameUpdater_viewer on Viewer {
241
+ name
242
+ }
243
+ `,
244
+ queryRef
245
+ );
246
+ const [newName, setNewName] = useState(data?.viewer?.name);
247
+ const onSubmit = () => {
248
+ commitLocalUpdate(environment, store => {
249
+ const {updatableData} = store.readUpdatableQuery(
250
+ graphql`
251
+ query NameUpdaterUpdateQuery @updatable {
252
+ viewer {
253
+ name
254
+ }
255
+ }
256
+ `,
257
+ {}
258
+ );
259
+ const viewer = updatableData.viewer;
260
+ if (viewer != null) {
261
+ viewer.name = newName;
262
+ }
263
+ });
264
+ };
265
+
266
+ // etc
267
+ }
268
+ ```
269
+
270
+ * This particular example can be rewritten using `readUpdatableFragment`. However, you may prefer `readUpdatableQuery` for several reasons:
271
+ * You do not have ready access to a fragment reference, e.g. if the call to `commitLocalUpdate` is not obviously associated with a component.
272
+ * You do not have ready access to a fragment where we select the **parent record** of the record we wish to modify (e.g. the `Query` in this example). Due to a known type hole in Relay, **updatable fragments cannot be spread at the top level.**
273
+ * You wish to use variables in the updatable fragment. Currently, updatable fragments reuse the variables that were passed to the query. This means that you cannot, for example, have an updatable fragment with fragment-local variables and call `readUpdatableFragment` multiple times, each time passing different variables.
274
+
275
+ <DocsRating />
@@ -0,0 +1,25 @@
1
+ ---
2
+ id: introduction
3
+ title: Introduction
4
+ slug: /guided-tour/updating-data/introduction
5
+ description: Relay guide to updating data
6
+ keywords:
7
+ - updating
8
+ - mutation
9
+ - useMutation
10
+ - commitMutation
11
+ - relay store
12
+ ---
13
+
14
+ import DocsRating from '@site/src/core/DocsRating';
15
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
16
+
17
+ In the Fetching Data section, we discuss how to fetch data using GraphQL queries. Though fetching data can have the *incidental* effect of modifying data in Relay's local store (if the fetched data has changed), we haven't discussed any ways to *intentionally* modify our locally stored data.
18
+
19
+ This section will do just that: it will discuss how to update our local data store, and data on the server.
20
+
21
+ :::note
22
+ The **Relay store** is a cache of GraphQL data, associated with a given Relay environment, that we have encountered during the execution of an application.
23
+ :::
24
+
25
+ <DocsRating />
@@ -0,0 +1,71 @@
1
+ ---
2
+ id: local-data-updates
3
+ title: Local Data Updates
4
+ slug: /guided-tour/updating-data/local-data-updates/
5
+ description: Other APIs for modifying store data
6
+ keywords:
7
+ - client-only
8
+ - commitLocalUpdate
9
+ - commitPayload
10
+ ---
11
+
12
+ import DocsRating from '@site/src/core/DocsRating';
13
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
14
+ // @fb-only
15
+
16
+ There are a couple of APIs that Relay provides in order to make purely local updates to the Relay store (i.e. updates not tied to a server operation).
17
+
18
+ Note that local data updates can be made both on [client-only data](../client-only-data/), or on regular data that was fetched from the server via an operation.
19
+
20
+ ## commitLocalUpdate
21
+
22
+ To make updates using an [`updater`](../imperatively-modifying-store-data/) function, you can use the `commitLocalUpdate` API:
23
+
24
+ ```js
25
+ import type {Environment} from 'react-relay';
26
+
27
+ const {commitLocalUpdate, graphql} = require('react-relay');
28
+
29
+ function commitCommentCreateLocally(
30
+ environment: Environment,
31
+ feedbackID: string,
32
+ ) {
33
+ return commitLocalUpdate(environment, store => {
34
+ // Imperatively mutate the store here
35
+ });
36
+ }
37
+
38
+ module.exports = {commit: commitCommentCreateLocally};
39
+ ```
40
+
41
+ * `commitLocalUpdate` update simply takes an environment and an updater function.
42
+ * `updater` takes a *`store`* argument, which is an instance of a [`RecordSourceSelectorProxy`](../../../api-reference/store/); this interface allows you to *imperatively* write and read data directly to and from the Relay store. This means that you have full control over how to update the store: you can *create entirely new records*, or *update or delete existing ones*.
43
+ * Unlike regular and optimistic updaters that are accepted by the mutation and subscription APIs, the updater passed to `commitLocalUpdate` does not accept a second parameter. This is because there is no associated network response.
44
+ * Note that any local data updates will automatically cause components subscribed to the data to be notified of the change and re-render.
45
+
46
+ ## commitPayload
47
+
48
+ `commitPayload` takes an `OperationDescriptor` and the payload for the query, and writes it to the Relay Store. The payload will be resolved like a normal server response for a query, and will also resolve Data Driven Dependencies that are passed as `JSResource`, `requireDefer`, etc.
49
+
50
+ ```js
51
+ import type {FooQueryRawResponse} from 'FooQuery.graphql'
52
+
53
+ const {createOperationDescriptor} = require('relay-runtime');
54
+
55
+ const operationDescriptor = createOperationDescriptor(FooQuery, {
56
+ id: 'an-id',
57
+ otherVariable: 'value',
58
+ });
59
+
60
+ const payload: FooQueryRawResponse = {...};
61
+
62
+ environment.commitPayload(operationDescriptor, payload);
63
+ ```
64
+
65
+ * An `OperationDescriptor` can be created by `createOperationDescriptor`; it takes the query and the query variables.
66
+ * The payload can be typed using the Flow type generated by adding the directive `@raw_response_type` to the query.
67
+ * Note that any local data updates will automatically cause components subscribed to the data to be notified of the change and re-render.
68
+
69
+ // @fb-only
70
+
71
+ <DocsRating />
@@ -0,0 +1,83 @@
1
+ ---
2
+ id: typesafe-updaters-faq
3
+ title: Typesafe updaters FAQ
4
+ slug: /guided-tour/updating-data/typesafe-updaters-faq/
5
+ description: Typesafe updater FAQ
6
+ keywords:
7
+ - typesafe updaters
8
+ - readUpdatableQuery
9
+ - readUpdatableFragment
10
+ - updater
11
+ - updatable
12
+ ---
13
+
14
+ import DocsRating from '@site/src/core/DocsRating';
15
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
16
+
17
+ # Typesafe Updaters FAQ
18
+
19
+ <FbInternalOnly>
20
+
21
+ :::note
22
+
23
+ Is something missing from this Q&A? Are you confused? Would you like help adopting these APIs? Please, reach out to [Robert Balicki](https://fb.workplace.com/profile.php?id=100042823931887). I am happy to help!
24
+
25
+ :::
26
+
27
+ </FbInternalOnly>
28
+
29
+ # General
30
+
31
+ ## What is typesafe updaters?
32
+
33
+ Typesafe updaters is the name given to a project to provide a typesafe and ergonomic alternative to the existing APIs for imperatively updating data in the Relay store.
34
+
35
+ For example, [`readUpdatableFragment`](../../../api-reference/store/#readupdatablefragmentfragment-updatablefragmenttfragmenttype-tdatafragmentreference-hasupdatablespreadtfragmenttype-updatabledatatdata) and [`readUpdatableQuery`](../../../api-reference/store/#readupdatablequeryquery-updatablequerytvariables-tdatavariables-tvariables-updatabledatatdata) are two typesafe updaters that the store exposes.
36
+
37
+ ## Why?
38
+
39
+ Relay provides typesafe and ergonomic APIs for fetching and managing data that originates on the server. In addition, Relay provides the ability to define local-only fields in **client schema extensions**. However, the APIs for mutating the data in these fields has hitherto been verbose and not ergonomic, meaning that we could not recommend Relay as a solution for managing local state.
40
+
41
+ ## What was wrong with the existing APIs?
42
+
43
+ The pre-existing APIs are verbose and not typesafe. They make it easy to make a variety of mistakes and require that the developer understand a new set of APIs only when writing updaters.
44
+
45
+ Typesafe updaters is a set of APIs that are typesafe and more ergonomic. They leverage well-known Relay idioms (queries, fragments, type refinement) and use getters and setters instead of requiring that the developer learn about a set of methods that are unused elsewhere.
46
+
47
+ ## How does a developer use typesafe updaters?
48
+
49
+ With typesafe updaters, a developers writes an updatable query or a fragment that specifies the data to imperatively update. Then, the developer reads out that data from the store, returning a so-called **updatable proxy**. Then, the developer mutates that updatable proxy. Mutating that updatable proxy using setters (e.g. `updatableData.name = "Godzilla"`) results in calls to the old API, but with added type safety.
50
+
51
+ ## What is an updatable query or fragment?
52
+
53
+ An updatable query or fragment is a query or fragment that has the `@updatable` directive.
54
+
55
+ # Updatable queries and fragments are not fetched
56
+
57
+ ## Are fields selected in updatable queries and fragments fetched from the server?
58
+
59
+ No! The server doesn't know about updatable queries and fragments. Their fields are never fetched.
60
+
61
+ Even if you spread an updatable fragment in a regular query or fragment, the fields selected by that updatable fragment are not fetched as part of that request.
62
+
63
+ ## What if I want to fetch a field and also mutate it?
64
+
65
+ You should select that field in both a regular query/fragment **and** in an updatable query/fragment.
66
+
67
+ ## What are some consequences of this?
68
+
69
+ * When you read out updatable data, it can be missing if it isn't present in the store.
70
+ * You cannot spread regular fragments in updatable queries/fragments.
71
+ * The generated artifact for updatable queries/fragments does not contain a query ID and does not contain a normalization AST (which is used for writing network data to the store.)
72
+ * Directives like `@defer`, etc. do not make sense in this context, and are disallowed.
73
+
74
+ # Misc
75
+
76
+ ## Where do I get a `store`?
77
+
78
+ The classes `RelayRecordSourceSelectorProxy`, `RecordSourceProxy` and `RelayRecordSourceProxy` contain the methods `readUpdatableQuery` and `readUpdatableFragment`. One can acquire an instance of these classes:
79
+
80
+ * In updaters of mutations and subscriptions
81
+ * In optimistic updaters of mutations
82
+ * When using `RelayModernEnvironment`'s `commitUpdate`, `applyUpdate`, etc. methods.
83
+ * When using the standalone `commitLocalUpdate` method.