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,279 @@
1
+ ---
2
+ id: graphql-subscriptions
3
+ title: GraphQL subscriptions
4
+ slug: /guided-tour/updating-data/graphql-subscriptions/
5
+ description: Relay guide to GraphQL subscriptions
6
+ keywords:
7
+ - subscription
8
+ ---
9
+
10
+ import DocsRating from '@site/src/core/DocsRating';
11
+ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal';
12
+
13
+ <FbInternalOnly>
14
+
15
+ [GraphQL subscriptions](https://our.internmc.facebook.com/intern/wiki/GraphQL_Subscriptions/) are a mechanism to allow clients to query for data in response to a stream of server-side events.
16
+
17
+ </FbInternalOnly>
18
+
19
+ <OssOnly>
20
+
21
+ GraphQL subscriptions are a mechanism to allow clients to query for data in response to a stream of server-side events.
22
+
23
+ </OssOnly>
24
+
25
+ A GraphQL subscription looks very similar to a query, except that it uses the `subscription` keyword:
26
+
27
+ ```graphql
28
+ subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) {
29
+ feedback_like_subscribe(data: $input) {
30
+ feedback {
31
+ like_count
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ * Establishing a subscription using this GraphQL snippet will cause the application to be notified whenever an event is emitted from the `feedback_like_subscribe` stream.
38
+ * `feedback_like_subscribe` is a *subscription root field* (or just *subscription field*), which sets up the subscription on the backend.
39
+
40
+ <FbInternalOnly>
41
+
42
+ :::info
43
+ You can view subscription 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 "Subscription".
44
+
45
+ You can click on the various mutation fields to see their parameters, descriptions and exposed fields.
46
+ :::
47
+
48
+ </FbInternalOnly>
49
+
50
+ * Like mutations, a subscription is handled in two separate steps. First, a server-side event occurs. Then, the query is executed.
51
+
52
+ :::note
53
+ Note that the event stream can be completely arbitrary, and can have no relation to the fields selected. In other words, there is no guarantee that the values selected in a subscription will have changed from notification to notification.
54
+ :::
55
+
56
+ * `feedback_like_subscribe` returns a specific GraphQL type which exposes the data we can query in response to the server-side event. In this case, we're querying for the Feedback object and its updated `like_count`. This allows us to show the like count in real time.
57
+
58
+ An example of a subscription payload received by the client could look like this:
59
+
60
+ ```json
61
+ {
62
+ "feedback_like_subscribe": {
63
+ "feedback": {
64
+ "id": "feedback-id",
65
+ "like_count": 321,
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ In Relay, we can declare GraphQL subscriptions using the `graphql` tag too:
72
+
73
+ ```js
74
+ const {graphql} = require('react-relay');
75
+
76
+ const feedbackLikeSubscription = graphql`
77
+ subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) {
78
+ feedback_like_subscribe(data: $input) {
79
+ feedback {
80
+ like_count
81
+ }
82
+ }
83
+ }
84
+ `;
85
+ ```
86
+
87
+ * Note that subscriptions can also reference GraphQL [variables](../../rendering/variables/) in the same way queries or fragments do.
88
+
89
+ ## Using `useSubscription` to create a subscription
90
+
91
+ In order to create a subscription in Relay, we can use the `useSubscription` and `requestSubscription` APIs. Let's take a look at an example using the `useSubscription` API:
92
+
93
+ ```js
94
+ import type {Environment} from 'react-relay';
95
+ import type {FeedbackLikeSubscribeData} from 'FeedbackLikeSubscription.graphql';
96
+
97
+ const {graphql, useSubscription} = require('react-relay');
98
+ const {useMemo} = require('React');
99
+
100
+ function useFeedbackSubscription(
101
+ input: FeedbackLikeSubscribeData,
102
+ ) {
103
+ const config = useMemo(() => ({
104
+ subscription: graphql`
105
+ subscription FeedbackLikeSubscription(
106
+ $input: FeedbackLikeSubscribeData!
107
+ ) {
108
+ feedback_like_subscribe(data: $input) {
109
+ feedback {
110
+ like_count
111
+ }
112
+ }
113
+ }
114
+ `,
115
+ variables: {input},
116
+ }), [input]);
117
+
118
+ return useSubscription(config);
119
+ }
120
+ ```
121
+
122
+ Let's distill what's happening here.
123
+
124
+ * `useSubscription` takes a `GraphQLSubscriptionConfig` object, which includes the following fields:
125
+ * `subscription`: the GraphQL literal containing the subscription, and
126
+ * `variables`: the variables with which to establish the subscription.
127
+ * In addition, `useSubscription` accepts a Flow type parameter. As with queries, the Flow type of the subscription is exported from the file that the Relay compiler generates.
128
+ * If this type is provided, the `GraphQLSubscriptionConfig` becomes statically typed as well. **It is a best practice to always provide this type.**
129
+ * Now, when the `useFeedbackSubscription` hook commits, Relay will establish a subscription.
130
+ * Unlike with APIs like `useLazyLoadQuery`, Relay will **not** attempt to establish this subscription during the render phase.
131
+ * Once it is established, whenever an event occurs, the backend will select the updated Feedback object and select the `like_count` fields off of it.
132
+ * Since the `Feedback` type contains an `id` field, the Relay compiler will automatically add a selection for the `id` field.
133
+ * When the subscription 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.
134
+ * If these values have changed as a result, any components which selected these fields off of the feedback object will be re-rendered. Or, to put it colloquially, any component which depends on the updated data will re-render.
135
+
136
+ :::note
137
+ The name of the type of the parameter `FeedbackLikeSubscribeData` is derived from the name of the top-level mutation field, i.e. from `feedback_like_subscribe`. This type is also exported from the generated `graphql.js` file.
138
+ :::
139
+
140
+ :::caution
141
+
142
+ The `GraphQLSubscriptionConfig` object passed to `useSubscription` should be memoized! Otherwise, `useSubscription` will dispose the subscription and re-establish it with every render!
143
+
144
+ :::
145
+
146
+ ## Refreshing components in response to subscription events
147
+
148
+ In the previous example, we manually selected `like_count`. Components that select this field will be re-rendered, should we receive an updated value.
149
+
150
+ However, it is generally better to spread fragments that correspond to the components that we want to refresh in response to the mutation. This is because the data selected by components can change.
151
+
152
+ Requiring developers to know about all subscriptions that might fetch their components data (and keeping them up-to-date) is an example of the kind of global reasoning that Relay wants to avoid requiring.
153
+
154
+ For example, we might rewrite the subscription as follows:
155
+
156
+ ```graphql
157
+ subscription FeedbackLikeSubscription($input: FeedbackLikeSubscribeData!) {
158
+ feedback_like_subscribe(data: $input) {
159
+ feedback {
160
+ ...FeedbackDisplay_feedback
161
+ ...FeedbackDetail_feedback
162
+ }
163
+ }
164
+ }
165
+ ```
166
+
167
+ Now, whenever a event in the `feedback_like_subscribe` event stream occurred, the data selected by the `FeedbackDisplay` and `FeedbackDetail` components will be refetched, and those components will remain in a consistent state.
168
+
169
+ :::note
170
+ Spreading fragments is generally preferable to refetching the data in response to subscription events, since the updated data can be fetched in a single round trip.
171
+ :::
172
+
173
+ ## Executing a callback when the subscription fires, errors or is closed by the server
174
+
175
+ In addition to writing updated data to the Relay store, we may want to execute a callback whenever a subscription payload is received (i.e. a subscription fires, an error is received, or the server ends the subscription). The `GraphQLSubscriptionConfig` can include the following fields to handle such cases:
176
+
177
+ * `onNext`, a callback that is executed when a subscription payload is received. It is passed the subscription response (stopping at fragment spread boundaries).
178
+ * `onError`, a callback that is executed when the subscription errors. It is passed the error that occurred.
179
+ * `onCompleted`, a callback that is executed when the server ends the subscription.
180
+
181
+ ## Declarative mutation directives
182
+
183
+ [Declarative mutation directives](../../list-data/updating-connections/#using-declarative-directives) and [`@deleteRecord`](../graphql-mutations/#deleting-items-in-response-to-mutations) work in subscriptions, too.
184
+
185
+ ### Manipulating connections in response to subscription events
186
+
187
+ Relay makes it easy to respond to subscription events by adding items to 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).
188
+
189
+ ### Deleting items in response to mutations
190
+
191
+ 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:
192
+
193
+ ```graphql
194
+ subscription DeletePostSubscription($input: DeletePostSubscribeData!) {
195
+ delete_post_subscribe(data: $input) {
196
+ deleted_post {
197
+ id @deleteRecord
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## Imperatively modifying local data
204
+
205
+ 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 `GraphQLSubscriptionConfig` accepts an `updater` function which gives you full control over how to update the store.
206
+
207
+ This is discussed in more detail in the section on [Imperatively updating store data](../imperatively-modifying-store-data/).
208
+
209
+ ## Configuring the Network Layer
210
+
211
+ <OssOnly>
212
+
213
+ You will need to Configure your [Network layer](../../../guides/network-layer) to handle subscriptions.
214
+
215
+ Usually GraphQL subscriptions are communicated over [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API), here's an example using [graphql-ws](https://github.com/enisdenjo/graphql-ws):
216
+
217
+ ```javascript
218
+ import {
219
+ ...
220
+ Network,
221
+ Observable
222
+ } from 'relay-runtime';
223
+ import { createClient } from 'graphql-ws';
224
+
225
+ const wsClient = createClient({
226
+ url:'ws://localhost:3000',
227
+ });
228
+
229
+ const subscribe = (operation, variables) => {
230
+ return Observable.create((sink) => {
231
+ return wsClient.subscribe(
232
+ {
233
+ operationName: operation.name,
234
+ query: operation.text,
235
+ variables,
236
+ },
237
+ sink,
238
+ );
239
+ });
240
+ }
241
+
242
+ const network = Network.create(fetchQuery, subscribe);
243
+ ```
244
+
245
+ Alternatively, the legacy [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) library can be used too:
246
+
247
+ ```javascript
248
+ import {
249
+ ...
250
+ Network,
251
+ Observable
252
+ } from 'relay-runtime';
253
+ import { SubscriptionClient } from 'subscriptions-transport-ws';
254
+
255
+ const subscriptionClient = new SubscriptionClient('ws://localhost:3000', {
256
+ reconnect: true,
257
+ });
258
+
259
+ const subscribe = (request, variables) => {
260
+ const subscribeObservable = subscriptionClient.request({
261
+ query: request.text,
262
+ operationName: request.name,
263
+ variables,
264
+ });
265
+ // Important: Convert subscriptions-transport-ws observable type to Relay's
266
+ return Observable.from(subscribeObservable);
267
+ };
268
+
269
+ const network = Network.create(fetchQuery, subscribe);
270
+ ```
271
+ </OssOnly>
272
+
273
+ <FbInternalOnly>
274
+
275
+ At Facebook, the Network Layer has already been configured to handle GraphQL Subscriptions. For more details on writing subscriptions at Facebook, check out this [guide](../../../guides/writing-subscriptions/). For a guide on setting up subscriptions on the server side, check out this [wiki](https://our.internmc.facebook.com/intern/wiki/GraphQL_Subscriptions/creating-a-new-subscription/).
276
+
277
+ </FbInternalOnly>
278
+
279
+ <DocsRating />