UNPKG

found-relay

Version:
165 lines (140 loc) 5.88 kB
import _awaitAsyncGenerator from "@babel/runtime/helpers/esm/awaitAsyncGenerator"; import _wrapAsyncGenerator from "@babel/runtime/helpers/esm/wrapAsyncGenerator"; import { dequal } from 'dequal'; import { accumulateRouteValues, checkResolved, getComponents, getRouteMatches, getRouteValues, isResolved // @ts-expect-error } from 'found/ResolverUtils'; import isPromise from 'is-promise'; import React from 'react'; import QuerySubscription from './QuerySubscription'; import ReadyStateRenderer from './ReadyStateRenderer'; import renderElement from './renderElement'; export default class Resolver { constructor(environment) { this.environment = environment; this.lastQuerySubscriptions = []; } createQuerySubscription(options) { return new QuerySubscription(options); } resolveElements(match) { var _this = this; return _wrapAsyncGenerator(function* () { const routeMatches = getRouteMatches(match); const Components = getComponents(routeMatches); const queries = getRouteValues(routeMatches, route => route.getQuery, route => route.query); const cacheConfigs = getRouteValues(routeMatches, route => route.getCacheConfig, route => route.cacheConfig); const fetchPolicies = getRouteValues(routeMatches, route => route.getFetchPolicy, route => route.fetchPolicy); const routeVariables = _this.getRouteVariables(match, routeMatches); const querySubscriptions = _this.updateQuerySubscriptions(queries, routeVariables, cacheConfigs, fetchPolicies); const fetches = querySubscriptions.map(querySubscription => querySubscription == null ? void 0 : querySubscription.fetch()); const earlyComponents = Components.some(isPromise) ? yield _awaitAsyncGenerator(Promise.all(Components.map(checkResolved))) : Components; const earlyData = yield _awaitAsyncGenerator(Promise.all(fetches.map(checkResolved))); let fetchedComponents; if (!earlyComponents.every(isResolved) || !earlyData.every(isResolved)) { const pendingElements = _this.createElements(routeMatches, earlyComponents, querySubscriptions, false); yield pendingElements.every(element => element !== undefined) ? pendingElements : undefined; fetchedComponents = yield _awaitAsyncGenerator(Promise.all(Components)); yield _awaitAsyncGenerator(Promise.all(fetches)); } else { fetchedComponents = earlyComponents; } yield _this.createElements(routeMatches, fetchedComponents, querySubscriptions, true); })(); } getRouteVariables(match, routeMatches) { return accumulateRouteValues(routeMatches, match.routeIndices, (variables, routeMatch) => { const { route, routeParams } = routeMatch; // We need to always run this to make sure we don't miss route params. let nextVariables = Object.assign({}, variables, routeParams); if (route.prepareVariables) { nextVariables = route.prepareVariables(nextVariables, routeMatch); } return nextVariables; }, null); } updateQuerySubscriptions(queries, routeVariables, cacheConfigs, fetchPolicies) { const querySubscriptions = queries.map((query, i) => { if (!query) { return null; } const variables = routeVariables[i]; const cacheConfig = cacheConfigs[i]; const fetchPolicy = fetchPolicies[i]; const lastQuerySubscription = this.lastQuerySubscriptions[i]; // Match the logic in <QueryRenderer> for not refetching. if (lastQuerySubscription && lastQuerySubscription.query === query && dequal(lastQuerySubscription.variables, variables) && dequal(lastQuerySubscription.cacheConfig, cacheConfig)) { this.lastQuerySubscriptions[i] = null; lastQuerySubscription.fetchPolicy = fetchPolicy; return lastQuerySubscription; } return this.createQuerySubscription({ environment: this.environment, query, variables, cacheConfig, fetchPolicy }); }); this.lastQuerySubscriptions.forEach(querySubscription => { if (querySubscription) { querySubscription.dispose(); } }); this.lastQuerySubscriptions = [...querySubscriptions]; return querySubscriptions; } createElements(routeMatches, Components, querySubscriptions, fetched) { return routeMatches.map((match, i) => { const { route, router } = match; const Component = Components[i]; const querySubscription = querySubscriptions[i]; const isComponentResolved = isResolved(Component); // Handle non-Relay routes. if (!querySubscription) { if (route.render) { return route.render({ match, Component: isComponentResolved ? Component : null, props: { match, router } }); } if (!isComponentResolved) { return undefined; } return Component ? /*#__PURE__*/React.createElement(Component, { match: match, router: router }) : null; } const resolvedComponent = isComponentResolved ? Component : null; const hasComponent = Component != null; const element = renderElement({ match, Component: resolvedComponent, isComponentResolved, hasComponent, querySubscription, resolving: true }); if (!element) { return element; } return routeChildren => /*#__PURE__*/React.createElement(ReadyStateRenderer, { match: match, Component: resolvedComponent, isComponentResolved: isComponentResolved, hasComponent: hasComponent, element: element, routeChildren: routeChildren, querySubscription: querySubscription, fetched: fetched }); }); } }