UNPKG

next-with-apollo

Version:
164 lines 7.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var react_1 = require("react"); function getProps(element) { return (element.props || element.attributes); } function isReactElement(element) { return !!element.type; } function isComponentClass(Comp) { return (Comp.prototype && (Comp.prototype.render || Comp.prototype.isReactComponent)); } function providesChildContext(instance) { return !!instance.getChildContext; } // Recurse a React Element tree, running visitor on each element. // If visitor returns `false`, don't call the element's render function // or recurse into its child elements function walkTree(element, context, visitor) { if (Array.isArray(element)) { element.forEach(function (item) { return walkTree(item, context, visitor); }); return; } if (!element) return; // a stateless functional component or a class if (isReactElement(element)) { if (typeof element.type === 'function') { var Comp = element.type; var props = Object.assign({}, Comp.defaultProps, getProps(element)); var childContext = context; var child = void 0; // Are we are a react class? // https://github.com/facebook/react/blob/master/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js#L66 if (isComponentClass(Comp)) { var instance_1 = new Comp(props, context); // In case the user doesn't pass these to super in the constructor instance_1.props = instance_1.props || props; instance_1.context = instance_1.context || context; // set the instance state to null (not undefined) if not set, to match React behaviour instance_1.state = instance_1.state || null; // Override setState to just change the state, not queue up an update. // (we can't do the default React thing as we aren't mounted "properly" // however, we don't need to re-render as well only support setState in // componentWillMount, which happens *before* render). instance_1.setState = function (newState) { if (typeof newState === 'function') { // React's TS type definitions don't contain context as a third parameter for // setState's updater function. // Remove this cast to `any` when that is fixed. newState = newState(instance_1.state, instance_1.props, instance_1.context); } instance_1.state = Object.assign({}, instance_1.state, newState); }; // this is a poor man's version of // https://github.com/facebook/react/blob/master/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js#L181 if (instance_1.componentWillMount) { instance_1.componentWillMount(); } if (providesChildContext(instance_1)) { childContext = Object.assign({}, context, instance_1.getChildContext()); } if (visitor(element, instance_1, context) === false) { return; } child = instance_1.render(); } else { // just a stateless functional if (visitor(element, null, context) === false) { return; } child = Comp(props, context); } if (child) { if (Array.isArray(child)) { child.forEach(function (item) { return walkTree(item, context, visitor); }); } else { walkTree(child, childContext, visitor); } } } else { // a basic string or dom element, just get children if (visitor(element, null, context) === false) { return; } if (element.props && element.props.children) { react_1.Children.forEach(element.props.children, function (child) { if (child) { walkTree(child, context, visitor); } }); } } } else if (typeof element === 'string' || typeof element === 'number') { // Just visit these, they are leaves so we don't keep traversing. visitor(element, null, context); } // TODO: Portals? } exports.walkTree = walkTree; function hasFetchDataFunction(instance) { return typeof instance.fetchData === 'function'; } function isPromise(query) { return typeof query.then === 'function'; } function getQueriesFromTree(_a, fetchRoot) { var rootElement = _a.rootElement, _b = _a.rootContext, rootContext = _b === void 0 ? {} : _b; if (fetchRoot === void 0) { fetchRoot = true; } var queries = []; walkTree(rootElement, rootContext, function (element, instance, context) { var skipRoot = !fetchRoot && element === rootElement; if (skipRoot) return; // console.log('IS', !!instance, isReactElement(element)); if (instance && isReactElement(element) && hasFetchDataFunction(instance)) { console.log('x', element); var query = instance.fetchData(); if (isPromise(query)) { queries.push({ query: query, element: element, context: context }); // Tell walkTree to not recurse inside this component; we will // wait for the query to execute before attempting it. return false; } } }); return queries; } // XXX component Cache function getDataFromTree(rootElement, rootContext, fetchRoot) { if (rootContext === void 0) { rootContext = {}; } if (fetchRoot === void 0) { fetchRoot = true; } var queries = getQueriesFromTree({ rootElement: rootElement, rootContext: rootContext }, fetchRoot); // no queries found, nothing to do if (!queries.length) return Promise.resolve(); var errors = []; // wait on each query that we found, re-rendering the subtree when it's done var mappedQueries = queries.map(function (_a) { var query = _a.query, element = _a.element, context = _a.context; // we've just grabbed the query for element, so don't try and get it again return query .then(function (_) { return getDataFromTree(element, context, false); }) .catch(function (e) { return errors.push(e); }); }); // Run all queries. If there are errors, still wait for all queries to execute // so the caller can ignore them if they wish. See https://github.com/apollographql/react-apollo/pull/488#issuecomment-284415525 return Promise.all(mappedQueries).then(function (_) { if (errors.length > 0) { var error = errors.length === 1 ? errors[0] : new Error(errors.length + " errors were thrown when executing your GraphQL queries."); error.queryErrors = errors; throw error; } }); } exports.default = getDataFromTree; //# sourceMappingURL=getDataFromTree.js.map