UNPKG

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