UNPKG

27.1 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 *
8 * @format
9 */
10// flowlint ambiguous-object-type:error
11'use strict';
12
13var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
14
15var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
16
17var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
18
19var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
20
21var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));
22
23var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
24
25var _objectSpread3 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
26
27var React = require('react');
28
29var ReactRelayContext = require('./ReactRelayContext');
30
31var ReactRelayQueryFetcher = require('./ReactRelayQueryFetcher');
32
33var areEqual = require("fbjs/lib/areEqual");
34
35var buildReactRelayContainer = require('./buildReactRelayContainer');
36
37var getRootVariablesForFragments = require('./getRootVariablesForFragments');
38
39var invariant = require("fbjs/lib/invariant");
40
41var warning = require("fbjs/lib/warning");
42
43var _require = require('./ReactRelayContainerUtils'),
44 getComponentName = _require.getComponentName,
45 getContainerName = _require.getContainerName;
46
47var _require2 = require('./RelayContext'),
48 assertRelayContext = _require2.assertRelayContext;
49
50var _require3 = require('relay-runtime'),
51 ConnectionInterface = _require3.ConnectionInterface,
52 Observable = _require3.Observable,
53 createFragmentSpecResolver = _require3.createFragmentSpecResolver,
54 createOperationDescriptor = _require3.createOperationDescriptor,
55 getDataIDsFromObject = _require3.getDataIDsFromObject,
56 getRequest = _require3.getRequest,
57 getSelector = _require3.getSelector,
58 getVariablesFromObject = _require3.getVariablesFromObject,
59 isScalarAndEqual = _require3.isScalarAndEqual;
60
61var FORWARD = 'forward';
62
63/**
64 * Extends the functionality of RelayFragmentContainer by providing a mechanism
65 * to load more data from a connection.
66 *
67 * # Configuring a PaginationContainer
68 *
69 * PaginationContainer accepts the standard FragmentContainer arguments and an
70 * additional `connectionConfig` argument:
71 *
72 * - `Component`: the component to be wrapped/rendered.
73 * - `fragments`: an object whose values are `graphql` fragments. The object
74 * keys determine the prop names by which fragment data is available.
75 * - `connectionConfig`: an object that determines how to load more connection
76 * data. Details below.
77 *
78 * # Loading More Data
79 *
80 * Use `props.relay.hasMore()` to determine if there are more items to load.
81 *
82 * ```
83 * hasMore(): boolean
84 * ```
85 *
86 * Use `props.relay.isLoading()` to determine if a previous call to `loadMore()`
87 * is still pending. This is convenient for avoiding duplicate load calls.
88 *
89 * ```
90 * isLoading(): boolean
91 * ```
92 *
93 * Use `props.relay.loadMore()` to load more items. This will return null if
94 * there are no more items to fetch, otherwise it will fetch more items and
95 * return a Disposable that can be used to cancel the fetch.
96 *
97 * `pageSize` should be the number of *additional* items to fetch (not the
98 * total).
99 *
100 * ```
101 * loadMore(pageSize: number, callback: ?(error: ?Error) => void): ?Disposable
102 * ```
103 *
104 * A complete example:
105 *
106 * ```
107 * class Foo extends React.Component {
108 * ...
109 * _onEndReached() {
110 * if (!this.props.relay.hasMore() || this.props.relay.isLoading()) {
111 * return;
112 * }
113 * this.props.relay.loadMore(10);
114 * }
115 * ...
116 * }
117 * ```
118 *
119 * # Connection Config
120 *
121 * Here's an example, followed by details of each config property:
122 *
123 * ```
124 * ReactRelayPaginationContainer.createContainer(
125 * Component,
126 * {
127 * user: graphql`fragment FriendsFragment on User {
128 * friends(after: $afterCursor first: $count) @connection {
129 * edges { ... }
130 * pageInfo {
131 * startCursor
132 * endCursor
133 * hasNextPage
134 * hasPreviousPage
135 * }
136 * }
137 * }`,
138 * },
139 * {
140 * direction: 'forward',
141 * getConnectionFromProps(props) {
142 * return props.user && props.user.friends;
143 * },
144 * getFragmentVariables(vars, totalCount) {
145 * // The component presumably wants *all* edges, not just those after
146 * // the cursor, so notice that we don't set $afterCursor here.
147 * return {
148 * ...vars,
149 * count: totalCount,
150 * };
151 * },
152 * getVariables(props, {count, cursor}, fragmentVariables) {
153 * return {
154 * id: props.user.id,
155 * afterCursor: cursor,
156 * count,
157 * },
158 * },
159 * query: graphql`
160 * query FriendsQuery($id: ID!, $afterCursor: ID, $count: Int!) {
161 * node(id: $id) {
162 * ...FriendsFragment
163 * }
164 * }
165 * `,
166 * }
167 * );
168 * ```
169 *
170 * ## Config Properties
171 *
172 * - `direction`: Either "forward" to indicate forward pagination using
173 * after/first, or "backward" to indicate backward pagination using
174 * before/last.
175 * - `getConnectionFromProps(props)`: PaginationContainer doesn't magically know
176 * which connection data you mean to fetch more of (a container might fetch
177 * multiple connections, but can only paginate one of them). This function is
178 * given the fragment props only (not full props), and should return the
179 * connection data. See the above example that returns the friends data via
180 * `props.user.friends`.
181 * - `getFragmentVariables(previousVars, totalCount)`: Given the previous variables
182 * and the new total number of items, get the variables to use when reading
183 * your fragments. Typically this means setting whatever your local "count"
184 * variable is to the value of `totalCount`. See the example.
185 * - `getVariables(props, {count, cursor})`: Get the variables to use when
186 * fetching the pagination `query`. You may determine the root object id from
187 * props (see the example that uses `props.user.id`) and may also set whatever
188 * variables you use for the after/first/before/last calls based on the count
189 * and cursor.
190 * - `query`: A query to use when fetching more connection data. This should
191 * typically reference one of the container's fragment (as in the example)
192 * to ensure that all the necessary fields for sub-components are fetched.
193 */
194function createGetConnectionFromProps(metadata) {
195 var path = metadata.path;
196 !path ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Unable to synthesize a ' + 'getConnectionFromProps function.') : invariant(false) : void 0;
197 return function (props) {
198 var data = props[metadata.fragmentName];
199
200 for (var i = 0; i < path.length; i++) {
201 if (!data || typeof data !== 'object') {
202 return null;
203 }
204
205 data = data[path[i]];
206 }
207
208 return data;
209 };
210}
211
212function createGetFragmentVariables(metadata) {
213 var countVariable = metadata.count;
214 !countVariable ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Unable to synthesize a ' + 'getFragmentVariables function.') : invariant(false) : void 0;
215 return function (prevVars, totalCount) {
216 return (0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, prevVars), {}, (0, _defineProperty2["default"])({}, countVariable, totalCount));
217 };
218}
219
220function findConnectionMetadata(fragments) {
221 var foundConnectionMetadata = null;
222 var isRelayModern = false;
223
224 for (var fragmentName in fragments) {
225 var fragment = fragments[fragmentName];
226 var connectionMetadata = fragment.metadata && fragment.metadata.connection; // HACK: metadata is always set to `undefined` in classic. In modern, even
227 // if empty, it is set to null (never undefined). We use that knowlege to
228 // check if we're dealing with classic or modern
229
230 if (fragment.metadata !== undefined) {
231 isRelayModern = true;
232 }
233
234 if (connectionMetadata) {
235 !(connectionMetadata.length === 1) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Only a single @connection is ' + 'supported, `%s` has %s.', fragmentName, connectionMetadata.length) : invariant(false) : void 0;
236 !!foundConnectionMetadata ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Only a single fragment with ' + '@connection is supported.') : invariant(false) : void 0;
237 foundConnectionMetadata = (0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, connectionMetadata[0]), {}, {
238 fragmentName: fragmentName
239 });
240 }
241 }
242
243 !(!isRelayModern || foundConnectionMetadata !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: A @connection directive must be present.') : invariant(false) : void 0;
244 return foundConnectionMetadata || {};
245}
246
247function toObserver(observerOrCallback) {
248 return typeof observerOrCallback === 'function' ? {
249 error: observerOrCallback,
250 complete: observerOrCallback,
251 unsubscribe: function unsubscribe(subscription) {
252 typeof observerOrCallback === 'function' && observerOrCallback();
253 }
254 } : observerOrCallback || {};
255}
256
257function createContainerWithFragments(Component, fragments, connectionConfig) {
258 var _class, _temp;
259
260 var componentName = getComponentName(Component);
261 var containerName = getContainerName(Component);
262 var metadata = findConnectionMetadata(fragments);
263 var getConnectionFromProps = connectionConfig.getConnectionFromProps || createGetConnectionFromProps(metadata);
264 var direction = connectionConfig.direction || metadata.direction;
265 !direction ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Unable to infer direction of the ' + 'connection, possibly because both first and last are provided.') : invariant(false) : void 0;
266 var getFragmentVariables = connectionConfig.getFragmentVariables || createGetFragmentVariables(metadata);
267 return _temp = _class = /*#__PURE__*/function (_React$Component) {
268 (0, _inheritsLoose2["default"])(_class, _React$Component);
269
270 function _class(props) {
271 var _this;
272
273 _this = _React$Component.call(this, props) || this;
274 (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_handleFragmentDataUpdate", function () {
275 _this.setState({
276 data: _this._resolver.resolve()
277 });
278 });
279 (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_hasMore", function () {
280 var connectionData = _this._getConnectionData();
281
282 return !!(connectionData && connectionData.hasMore && connectionData.cursor);
283 });
284 (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_isLoading", function () {
285 return !!_this._refetchSubscription;
286 });
287 (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_refetchConnection", function (totalCount, observerOrCallback, refetchVariables) {
288 if (!_this._canFetchPage('refetchConnection')) {
289 return {
290 dispose: function dispose() {}
291 };
292 }
293
294 _this._refetchVariables = refetchVariables;
295 var paginatingVariables = {
296 count: totalCount,
297 cursor: null,
298 totalCount: totalCount
299 };
300
301 var fetch = _this._fetchPage(paginatingVariables, toObserver(observerOrCallback), {
302 force: true
303 });
304
305 return {
306 dispose: fetch.unsubscribe
307 };
308 });
309 (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_loadMore", function (pageSize, observerOrCallback, options) {
310 if (!_this._canFetchPage('loadMore')) {
311 return {
312 dispose: function dispose() {}
313 };
314 }
315
316 var observer = toObserver(observerOrCallback);
317
318 var connectionData = _this._getConnectionData();
319
320 if (!connectionData) {
321 Observable.create(function (sink) {
322 return sink.complete();
323 }).subscribe(observer);
324 return null;
325 }
326
327 var totalCount = connectionData.edgeCount + pageSize;
328
329 if (options && options.force) {
330 return _this._refetchConnection(totalCount, observerOrCallback);
331 }
332
333 var _ConnectionInterface$ = ConnectionInterface.get(),
334 END_CURSOR = _ConnectionInterface$.END_CURSOR,
335 START_CURSOR = _ConnectionInterface$.START_CURSOR;
336
337 var cursor = connectionData.cursor;
338 process.env.NODE_ENV !== "production" ? warning(cursor != null && cursor !== '', 'ReactRelayPaginationContainer: Cannot `loadMore` without valid `%s` (got `%s`)', direction === FORWARD ? END_CURSOR : START_CURSOR, cursor) : void 0;
339 var paginatingVariables = {
340 count: pageSize,
341 cursor: cursor,
342 totalCount: totalCount
343 };
344
345 var fetch = _this._fetchPage(paginatingVariables, observer, options);
346
347 return {
348 dispose: fetch.unsubscribe
349 };
350 });
351 var relayContext = assertRelayContext(props.__relayContext);
352 _this._isARequestInFlight = false;
353 _this._refetchSubscription = null;
354 _this._refetchVariables = null;
355 _this._resolver = createFragmentSpecResolver(relayContext, containerName, fragments, props, _this._handleFragmentDataUpdate);
356 _this.state = {
357 data: _this._resolver.resolve(),
358 prevContext: relayContext,
359 contextForChildren: relayContext,
360 relayProp: _this._buildRelayProp(relayContext)
361 };
362 _this._isUnmounted = false;
363 _this._hasFetched = false;
364 return _this;
365 }
366 /**
367 * When new props are received, read data for the new props and subscribe
368 * for updates. Props may be the same in which case previous data and
369 * subscriptions can be reused.
370 */
371
372
373 var _proto = _class.prototype;
374
375 _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) {
376 var relayContext = assertRelayContext(nextProps.__relayContext);
377 var prevIDs = getDataIDsFromObject(fragments, this.props);
378 var nextIDs = getDataIDsFromObject(fragments, nextProps);
379 var prevRootVariables = getRootVariablesForFragments(fragments, this.props);
380 var nextRootVariables = getRootVariablesForFragments(fragments, nextProps); // If the environment has changed or props point to new records then
381 // previously fetched data and any pending fetches no longer apply:
382 // - Existing references are on the old environment.
383 // - Existing references are based on old variables.
384 // - Pending fetches are for the previous records.
385
386 if (relayContext.environment !== this.state.prevContext.environment || !areEqual(prevRootVariables, nextRootVariables) || !areEqual(prevIDs, nextIDs)) {
387 this._cleanup(); // Child containers rely on context.relay being mutated (for gDSFP).
388
389
390 this._resolver = createFragmentSpecResolver(relayContext, containerName, fragments, nextProps, this._handleFragmentDataUpdate);
391 this.setState({
392 prevContext: relayContext,
393 contextForChildren: relayContext,
394 relayProp: this._buildRelayProp(relayContext)
395 });
396 } else if (!this._hasFetched) {
397 this._resolver.setProps(nextProps);
398 }
399
400 var data = this._resolver.resolve();
401
402 if (data !== this.state.data) {
403 this.setState({
404 data: data
405 });
406 }
407 };
408
409 _proto.componentWillUnmount = function componentWillUnmount() {
410 this._isUnmounted = true;
411
412 this._cleanup();
413 };
414
415 _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
416 // Short-circuit if any Relay-related data has changed
417 if (nextState.data !== this.state.data || nextState.relayProp !== this.state.relayProp) {
418 return true;
419 } // Otherwise, for convenience short-circuit if all non-Relay props
420 // are scalar and equal
421
422
423 var keys = Object.keys(nextProps);
424
425 for (var ii = 0; ii < keys.length; ii++) {
426 var _key = keys[ii];
427
428 if (_key === '__relayContext') {
429 if (nextState.prevContext.environment !== this.state.prevContext.environment) {
430 return true;
431 }
432 } else {
433 if (!fragments.hasOwnProperty(_key) && !isScalarAndEqual(nextProps[_key], this.props[_key])) {
434 return true;
435 }
436 }
437 }
438
439 return false;
440 };
441
442 _proto._buildRelayProp = function _buildRelayProp(relayContext) {
443 return {
444 hasMore: this._hasMore,
445 isLoading: this._isLoading,
446 loadMore: this._loadMore,
447 refetchConnection: this._refetchConnection,
448 environment: relayContext.environment
449 };
450 }
451 /**
452 * Render new data for the existing props/context.
453 */
454 ;
455
456 _proto._getConnectionData = function _getConnectionData() {
457 // Extract connection data and verify there are more edges to fetch
458 var _this$props = this.props,
459 _ = _this$props.componentRef,
460 restProps = (0, _objectWithoutPropertiesLoose2["default"])(_this$props, ["componentRef"]);
461 var props = (0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, restProps), this.state.data);
462 var connectionData = getConnectionFromProps(props);
463
464 if (connectionData == null) {
465 return null;
466 }
467
468 var _ConnectionInterface$2 = ConnectionInterface.get(),
469 EDGES = _ConnectionInterface$2.EDGES,
470 PAGE_INFO = _ConnectionInterface$2.PAGE_INFO,
471 HAS_NEXT_PAGE = _ConnectionInterface$2.HAS_NEXT_PAGE,
472 HAS_PREV_PAGE = _ConnectionInterface$2.HAS_PREV_PAGE,
473 END_CURSOR = _ConnectionInterface$2.END_CURSOR,
474 START_CURSOR = _ConnectionInterface$2.START_CURSOR;
475
476 !(typeof connectionData === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Expected `getConnectionFromProps()` in `%s`' + 'to return `null` or a plain object with %s and %s properties, got `%s`.', componentName, EDGES, PAGE_INFO, connectionData) : invariant(false) : void 0;
477 var edges = connectionData[EDGES];
478 var pageInfo = connectionData[PAGE_INFO];
479
480 if (edges == null || pageInfo == null) {
481 return null;
482 }
483
484 !Array.isArray(edges) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Expected `getConnectionFromProps()` in `%s`' + 'to return an object with %s: Array, got `%s`.', componentName, EDGES, edges) : invariant(false) : void 0;
485 !(typeof pageInfo === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Expected `getConnectionFromProps()` in `%s`' + 'to return an object with %s: Object, got `%s`.', componentName, PAGE_INFO, pageInfo) : invariant(false) : void 0;
486 var hasMore = direction === FORWARD ? pageInfo[HAS_NEXT_PAGE] : pageInfo[HAS_PREV_PAGE];
487 var cursor = direction === FORWARD ? pageInfo[END_CURSOR] : pageInfo[START_CURSOR];
488
489 if (typeof hasMore !== 'boolean' || edges.length !== 0 && typeof cursor === 'undefined') {
490 process.env.NODE_ENV !== "production" ? warning(false, 'ReactRelayPaginationContainer: Cannot paginate without %s fields in `%s`. ' + 'Be sure to fetch %s (got `%s`) and %s (got `%s`).', PAGE_INFO, componentName, direction === FORWARD ? HAS_NEXT_PAGE : HAS_PREV_PAGE, hasMore, direction === FORWARD ? END_CURSOR : START_CURSOR, cursor) : void 0;
491 return null;
492 }
493
494 return {
495 cursor: cursor,
496 edgeCount: edges.length,
497 hasMore: hasMore
498 };
499 };
500
501 _proto._getQueryFetcher = function _getQueryFetcher() {
502 if (!this._queryFetcher) {
503 this._queryFetcher = new ReactRelayQueryFetcher();
504 }
505
506 return this._queryFetcher;
507 };
508
509 _proto._canFetchPage = function _canFetchPage(method) {
510 if (this._isUnmounted) {
511 process.env.NODE_ENV !== "production" ? warning(false, 'ReactRelayPaginationContainer: Unexpected call of `%s` ' + 'on unmounted container `%s`. It looks like some instances ' + 'of your container still trying to fetch data but they already ' + 'unmounted. Please make sure you clear all timers, intervals, async ' + 'calls, etc that may trigger `%s` call.', method, containerName, method) : void 0;
512 return false;
513 }
514
515 return true;
516 };
517
518 _proto._fetchPage = function _fetchPage(paginatingVariables, observer, options) {
519 var _this2 = this;
520
521 var _assertRelayContext = assertRelayContext(this.props.__relayContext),
522 environment = _assertRelayContext.environment;
523
524 var _this$props2 = this.props,
525 _ = _this$props2.componentRef,
526 __relayContext = _this$props2.__relayContext,
527 restProps = (0, _objectWithoutPropertiesLoose2["default"])(_this$props2, ["componentRef", "__relayContext"]);
528 var props = (0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, restProps), this.state.data);
529 var fragmentVariables;
530 var rootVariables = getRootVariablesForFragments(fragments, restProps);
531 fragmentVariables = getVariablesFromObject(fragments, restProps);
532 fragmentVariables = (0, _objectSpread3["default"])((0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, rootVariables), fragmentVariables), this._refetchVariables);
533 var fetchVariables = connectionConfig.getVariables(props, {
534 count: paginatingVariables.count,
535 cursor: paginatingVariables.cursor
536 }, fragmentVariables);
537 !(typeof fetchVariables === 'object' && fetchVariables !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'ReactRelayPaginationContainer: Expected `getVariables()` to ' + 'return an object, got `%s` in `%s`.', fetchVariables, componentName) : invariant(false) : void 0;
538 fetchVariables = (0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, fetchVariables), this._refetchVariables);
539 fragmentVariables = (0, _objectSpread3["default"])((0, _objectSpread3["default"])({}, fetchVariables), fragmentVariables);
540 var cacheConfig = options ? {
541 force: !!options.force
542 } : undefined;
543
544 if (cacheConfig != null && (options === null || options === void 0 ? void 0 : options.metadata) != null) {
545 cacheConfig.metadata = options === null || options === void 0 ? void 0 : options.metadata;
546 }
547
548 var request = getRequest(connectionConfig.query);
549 var operation = createOperationDescriptor(request, fetchVariables, cacheConfig);
550 var refetchSubscription = null;
551
552 if (this._refetchSubscription) {
553 this._refetchSubscription.unsubscribe();
554 }
555
556 this._hasFetched = true;
557
558 var onNext = function onNext(payload, complete) {
559 var prevData = _this2._resolver.resolve();
560
561 _this2._resolver.setVariables(getFragmentVariables(fragmentVariables, paginatingVariables.totalCount), operation.request.node);
562
563 var nextData = _this2._resolver.resolve(); // Workaround slightly different handling for connection in different
564 // core implementations:
565 // - Classic core requires the count to be explicitly incremented
566 // - Modern core automatically appends new items, updating the count
567 // isn't required to see new data.
568 //
569 // `setState` is only required if changing the variables would change the
570 // resolved data.
571 // TODO #14894725: remove PaginationContainer equal check
572
573
574 if (!areEqual(prevData, nextData)) {
575 _this2.setState({
576 data: nextData,
577 contextForChildren: {
578 environment: _this2.props.__relayContext.environment
579 }
580 }, complete);
581 } else {
582 complete();
583 }
584 };
585
586 var cleanup = function cleanup() {
587 if (_this2._refetchSubscription === refetchSubscription) {
588 _this2._refetchSubscription = null;
589 _this2._isARequestInFlight = false;
590 }
591 };
592
593 this._isARequestInFlight = true;
594 refetchSubscription = this._getQueryFetcher().execute({
595 environment: environment,
596 operation: operation,
597 preservePreviousReferences: true
598 }).mergeMap(function (payload) {
599 return Observable.create(function (sink) {
600 onNext(payload, function () {
601 sink.next(); // pass void to public observer's `next`
602
603 sink.complete();
604 });
605 });
606 }) // use do instead of finally so that observer's `complete` fires after cleanup
607 ["do"]({
608 error: cleanup,
609 complete: cleanup,
610 unsubscribe: cleanup
611 }).subscribe(observer || {});
612 this._refetchSubscription = this._isARequestInFlight ? refetchSubscription : null;
613 return refetchSubscription;
614 };
615
616 _proto._cleanup = function _cleanup() {
617 this._resolver.dispose();
618
619 this._refetchVariables = null;
620 this._hasFetched = false;
621
622 if (this._refetchSubscription) {
623 this._refetchSubscription.unsubscribe();
624
625 this._refetchSubscription = null;
626 this._isARequestInFlight = false;
627 }
628
629 if (this._queryFetcher) {
630 this._queryFetcher.dispose();
631 }
632 };
633
634 _proto.render = function render() {
635 var _this$props3 = this.props,
636 componentRef = _this$props3.componentRef,
637 __relayContext = _this$props3.__relayContext,
638 props = (0, _objectWithoutPropertiesLoose2["default"])(_this$props3, ["componentRef", "__relayContext"]);
639 return /*#__PURE__*/React.createElement(ReactRelayContext.Provider, {
640 value: this.state.contextForChildren
641 }, /*#__PURE__*/React.createElement(Component, (0, _extends2["default"])({}, props, this.state.data, {
642 ref: componentRef,
643 relay: this.state.relayProp
644 })));
645 };
646
647 return _class;
648 }(React.Component), (0, _defineProperty2["default"])(_class, "displayName", containerName), _temp;
649}
650/**
651 * Wrap the basic `createContainer()` function with logic to adapt to the
652 * `context.relay.environment` in which it is rendered. Specifically, the
653 * extraction of the environment-specific version of fragments in the
654 * `fragmentSpec` is memoized once per environment, rather than once per
655 * instance of the container constructed/rendered.
656 */
657
658
659function createContainer(Component, fragmentSpec, connectionConfig) {
660 // $FlowFixMe[incompatible-return]
661 return buildReactRelayContainer(Component, fragmentSpec, function (ComponentClass, fragments) {
662 return createContainerWithFragments(ComponentClass, fragments, connectionConfig);
663 });
664}
665
666module.exports = {
667 createContainer: createContainer
668};
\No newline at end of file