UNPKG

react-relay

Version:

A framework for building GraphQL-driven React applications.

233 lines (220 loc) • 7.02 kB
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict-local * @format * @oncall relay */ 'use strict'; import type {OperationType} from '../../relay-runtime/util/RelayRuntimeTypes'; import type { EntryPoint, EntryPointComponent, EnvironmentProviderOptions, IEnvironmentProvider, PreloadedQuery, } from './EntryPointTypes.flow'; const preloadQuery_DEPRECATED = require('./preloadQuery_DEPRECATED'); const ProfilerContext = require('./ProfilerContext'); const useRelayEnvironment = require('./useRelayEnvironment'); const React = require('react'); const {useContext, useEffect, useMemo} = require('react'); const {stableCopy} = require('relay-runtime'); type PreloadedEntryPoint<TEntryPointComponent> = $ReadOnly<{ entryPoints: React.ElementConfig<TEntryPointComponent>['entryPoints'], extraProps: React.ElementConfig<TEntryPointComponent>['extraProps'], getComponent: () => TEntryPointComponent, queries: React.ElementConfig<TEntryPointComponent>['queries'], rootModuleID: string, }>; type EntryPointContainerProps< TEntryPointParams, TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, > = $ReadOnly< $ReadOnly<{ entryPoint: EntryPoint< TEntryPointParams, EntryPointComponent< TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, >, >, entryPointParams: TEntryPointParams, environmentProvider?: IEnvironmentProvider<EnvironmentProviderOptions>, props: TRuntimeProps, }>, >; function stableStringify(value: mixed): string { return JSON.stringify(stableCopy(value)) ?? 'null'; } function prepareEntryPoint< TEntryPointParams: {...}, // $FlowExpectedError[unclear-type] Need any to make it supertype of all PreloadedQuery TPreloadedQueries: {+[string]: PreloadedQuery<any>}, TPreloadedEntryPoints: {...}, TRuntimeProps: {...}, TExtraProps, TEntryPointComponent: EntryPointComponent< TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, >, TEntryPoint: EntryPoint<TEntryPointParams, TEntryPointComponent>, >( environmentProvider: IEnvironmentProvider<EnvironmentProviderOptions>, entryPoint: TEntryPoint, entryPointParams: TEntryPointParams, ): PreloadedEntryPoint<TEntryPointComponent> { // Start loading the code for the entrypoint let loadingPromise = null; if (entryPoint.root.getModuleIfRequired() == null) { loadingPromise = entryPoint.root.load(); } const preloadProps = entryPoint.getPreloadProps(entryPointParams); const {queries, entryPoints, extraProps} = preloadProps; // $FlowFixMe[incompatible-type] const preloadedQueries: Partial<TPreloadedQueries> = {}; // $FlowFixMe[incompatible-type] const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {}; if (queries != null) { const queriesPropNames = Object.keys(queries); queriesPropNames.forEach(queryPropName => { const {environmentProviderOptions, options, parameters, variables} = queries[queryPropName]; const environment = environmentProvider.getEnvironment( environmentProviderOptions, ); // $FlowFixMe[incompatible-type] preloadedQueries[queryPropName] = preloadQuery_DEPRECATED< OperationType, mixed, >( environment, parameters, variables, options, environmentProviderOptions, ); }); } if (entryPoints != null) { const entryPointPropNames = Object.keys(entryPoints); entryPointPropNames.forEach(entryPointPropName => { const entryPointDescription = entryPoints[entryPointPropName]; if (entryPointDescription == null) { return; } const {entryPoint: nestedEntryPoint, entryPointParams: nestedParams} = entryPointDescription; preloadedEntryPoints[entryPointPropName] = prepareEntryPoint< _, {}, {...}, {...}, mixed, EntryPointComponent<{}, {...}, {...}, mixed>, _, >(environmentProvider, nestedEntryPoint, nestedParams); }); } return { entryPoints: (preloadedEntryPoints: TPreloadedEntryPoints), extraProps: extraProps ?? null, getComponent: () => { const component = entryPoint.root.getModuleIfRequired(); if (component == null) { loadingPromise = loadingPromise ?? entryPoint.root.load(); throw loadingPromise; } // $FlowFixMe[incompatible-cast] - trust me Flow, its entryPoint component return (component: TEntryPointComponent); }, queries: (preloadedQueries: TPreloadedQueries), rootModuleID: entryPoint.root.getModuleId(), }; } function LazyLoadEntryPointContainer_DEPRECATED< TEntryPointParams: {...}, // $FlowExpectedError[unclear-type] Need any to make it supertype of all PreloadedQuery TPreloadedQueries: {+[string]: PreloadedQuery<any>}, TPreloadedEntryPoints: {...}, TRuntimeProps: {...}, TExtraProps, >({ entryPoint, entryPointParams, props, environmentProvider, }: EntryPointContainerProps< TEntryPointParams, TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, >): React.MixedElement { const environment = useRelayEnvironment(); const {getPreloadProps} = entryPoint; // IMPORTANT: Loading the component may suspend (throw), so the props // *must* be computed first to fetch the component's data-dependencies in // parallel with the component itself (the code). const entryPointParamsHash = stableStringify(entryPointParams); const {getComponent, queries, entryPoints, extraProps, rootModuleID} = useMemo(() => { return prepareEntryPoint< TEntryPointParams, TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, EntryPointComponent< TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, >, _, >( environmentProvider ?? { getEnvironment: () => environment, }, entryPoint, entryPointParams, ); // NOTE: stableParams encodes the information from params // eslint-disable-next-line react-hooks/exhaustive-deps }, [ environment, environmentProvider, getPreloadProps, entryPointParamsHash, ]); const Component = useMemo(() => { return getComponent(); }, [getComponent]); const profilerContext = useContext(ProfilerContext); useEffect(() => { environment.__log({ name: 'entrypoint.root.consume', profilerContext, rootModuleID, }); }, [environment, profilerContext, rootModuleID]); return ( <Component entryPoints={entryPoints} extraProps={extraProps} props={props} queries={queries} /> ); } module.exports = LazyLoadEntryPointContainer_DEPRECATED;