@remix-relay/react
Version:
Provides Relay integration with React Router (Framework)
1 lines • 13.6 kB
Source Map (JSON)
{"version":3,"sources":["../src/Deferred.tsx","../src/deferred-query-context.tsx","../src/client-loader-query.ts","../src/get-cached-response.ts","../src/meta-query.ts","../src/useLoaderQuery.ts"],"sourcesContent":["import { Suspense, SuspenseProps, use, useEffect, useState } from \"react\";\nimport { Await } from \"react-router\";\nimport { DeferredQueryContext } from \"./deferred-query-context\";\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n if (!mounted && typeof window !== \"undefined\") {\n setMounted(true);\n }\n }, [mounted]);\n\n const deferredQuery = use(DeferredQueryContext);\n\n return mounted ? (\n <Suspense {...rest}>\n {deferredQuery ? (\n <Await resolve={deferredQuery}>{children}</Await>\n ) : (\n children\n )}\n </Suspense>\n ) : (\n <>{rest.fallback}</>\n );\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from \"react\";\nimport { createContext, useState } from \"react\";\n\nexport const DeferredQueryContext = createContext<Promise<any> | null>(null);\nexport const SetDeferredQueryContext = createContext<\n Dispatch<SetStateAction<Promise<any> | null>>\n>(() => {});\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const [deferredQueries, setDeferredQueries] = useState<Promise<any> | null>(\n null,\n );\n\n return (\n <SetDeferredQueryContext value={setDeferredQueries}>\n <DeferredQueryContext value={deferredQueries}>\n {children}\n </DeferredQueryContext>\n </SetDeferredQueryContext>\n );\n}\n","import relay from \"react-relay\";\nimport type {\n Environment,\n GraphQLTaggedNode,\n OperationType,\n VariablesOf,\n} from \"relay-runtime\";\n\nconst { fetchQuery, loadQuery } = relay;\n\nexport function getClientLoaderQuery(environment: Environment) {\n return async <TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n ) => clientLoaderQuery(environment, query, variables);\n}\n\nexport async function clientLoaderQuery<TQuery extends OperationType>(\n environment: Environment,\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n) {\n const data = await fetchQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-or-network\",\n }).toPromise();\n\n const queryRef = loadQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-only\",\n });\n\n return { queryRef, data };\n}\n","import type {\n CacheConfig,\n GraphQLResponse,\n RequestParameters,\n Variables,\n} from \"relay-runtime\";\nimport { Observable, QueryResponseCache } from \"relay-runtime\";\n\nexport const responseCache: QueryResponseCache = new QueryResponseCache({\n size: 100,\n ttl: 5000,\n});\n\nexport function getCachedResponse(\n params: RequestParameters,\n variables: Variables,\n cacheConfig: CacheConfig,\n) {\n const isQuery = params.operationKind === \"query\";\n const cacheKey = params.id ?? params.cacheID;\n const forceFetch = cacheConfig && cacheConfig.force;\n\n if (responseCache === null || !isQuery || forceFetch) {\n return null;\n }\n\n const fromCache = responseCache.get(cacheKey, variables);\n\n const deferredFromCache: GraphQLResponse[] = [];\n\n for (let i = 0; ; i++) {\n const deferred = responseCache.get(`${cacheKey}-${i}`, variables);\n if (!deferred) break;\n deferredFromCache.push(deferred);\n }\n\n if (fromCache === null) {\n return null;\n }\n\n return Observable.create((sink) => {\n sink.next(fromCache);\n\n for (const deferred of deferredFromCache) {\n sink.next(deferred);\n }\n\n sink.complete();\n });\n}\n","/* eslint-disable no-unused-vars */\nimport type { MetaFunction } from \"react-router\";\nimport type { OperationType } from \"relay-runtime\";\n\nexport function metaQuery<TQuery extends OperationType>(\n metaFunction: (\n args: Parameters<MetaFunction>[0] & {\n data: TQuery[\"response\"];\n },\n ) => ReturnType<MetaFunction>,\n): MetaFunction<\n () =>\n | { preloadedQuery: { response: { data: TQuery[\"response\"] } } }\n | { data: TQuery[\"response\"] }\n> {\n return ({ data, ...rest }) => {\n const metaData: TQuery[\"response\"] =\n data && \"data\" in data\n ? data.data\n : data && \"preloadedQuery\" in data\n ? (data.preloadedQuery.response as { data: TQuery[\"response\"] }).data\n : null;\n\n return metaFunction({\n data: metaData,\n ...rest,\n });\n };\n}\n","import { use, useEffect, useMemo, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type {\n GraphQLTaggedNode,\n PreloadFetchPolicy,\n PreloadedQuery,\n} from \"react-relay\";\nimport relay from \"react-relay\";\nimport type { useQueryLoaderHookType } from \"react-relay/relay-hooks/useQueryLoader\";\nimport { useLoaderData, useRouteLoaderData } from \"react-router\";\nimport type {\n ConcreteRequest,\n GraphQLResponse,\n OperationType,\n RequestParameters,\n VariablesOf,\n} from \"relay-runtime\";\nimport invariant from \"tiny-invariant\";\nimport { SetDeferredQueryContext } from \"./deferred-query-context\";\nimport { responseCache } from \"./get-cached-response\";\n\nconst { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay;\n\nexport type SerializablePreloadedQuery<TQuery extends OperationType> = {\n params: ConcreteRequest[\"params\"];\n variables: VariablesOf<TQuery>;\n response: GraphQLResponse;\n};\n\ntype LoaderData<TQuery extends OperationType> =\n | {\n preloadedQuery: SerializablePreloadedQuery<TQuery>;\n deferredQueries: Promise<SerializablePreloadedQuery<TQuery>[]>;\n }\n | { queryRef: PreloadedQuery<TQuery> };\n\nfunction useCommonLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy,\n loaderData: LoaderData<TQuery>,\n): [\n TQuery[\"response\"],\n useQueryLoaderHookType<TQuery>[1],\n useQueryLoaderHookType<TQuery>[2],\n] {\n const preloadedQuery =\n \"preloadedQuery\" in loaderData\n ? (loaderData.preloadedQuery as unknown as SerializablePreloadedQuery<TQuery>)\n : null;\n\n const deferredQueries =\n \"deferredQueries\" in loaderData\n ? (loaderData.deferredQueries as unknown as Promise<\n SerializablePreloadedQuery<TQuery>[]\n >)\n : null;\n\n const [deferredResult, setDeferredResult] = useState(preloadedQuery);\n\n const setDeferredQueries = use(SetDeferredQueryContext);\n\n useEffect(() => {\n if (deferredQueries) {\n setDeferredQueries(\n deferredQueries.then(async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n\n return deferredResults;\n }),\n );\n }\n }, [deferredQueries, preloadedQuery, setDeferredQueries, setDeferredResult]);\n\n const environment = useRelayEnvironment();\n\n useMemo(() => {\n if (deferredResult) {\n writePreloadedQueryToCache(deferredResult);\n }\n }, [deferredResult]);\n\n let ref: PreloadedQuery<TQuery> | null =\n \"queryRef\" in loaderData\n ? (loaderData.queryRef as unknown as PreloadedQuery<TQuery>)\n : deferredResult\n ? {\n environment,\n fetchKey: `${\n deferredResult.params.id ?? deferredResult.params.cacheID\n }${simpleHash(deferredResult.response)}`,\n fetchPolicy,\n isDisposed: false,\n name: deferredResult.params.name,\n kind: \"PreloadedQuery\",\n variables: deferredResult.variables,\n dispose: () => {},\n }\n : null;\n\n invariant(ref, \"Missing queryRef\");\n\n const [queryRef, loadQuery, disposeQuery] = useQueryLoader<TQuery>(query);\n\n if (queryRef) ref = queryRef;\n\n const reloadQuery: typeof loadQuery = (\n variables,\n options = { fetchPolicy: \"store-and-network\" },\n ) => loadQuery(variables, options);\n\n const data = usePreloadedQuery<TQuery>(query, ref);\n\n return [data, reloadQuery, disposeQuery];\n}\n\nexport function useLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> = useLoaderData();\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nexport function useRouteLoaderQuery<TQuery extends OperationType>(\n routeId: string,\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> | undefined =\n useRouteLoaderData(routeId);\n\n invariant(loaderData, `Missing loader data for routeId ${routeId}`);\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nfunction writePreloadedQueryToCache<TQuery extends OperationType>(\n preloadedQueryObject: SerializablePreloadedQuery<TQuery>,\n) {\n const params = preloadedQueryObject.params as RequestParameters & {\n cacheID?: string;\n };\n\n const cacheKey = params.cacheID ?? params.id;\n invariant(cacheKey, \"Missing cacheKey\");\n\n responseCache?.set(\n cacheKey,\n preloadedQueryObject.variables,\n preloadedQueryObject.response,\n );\n}\n\nfunction simpleHash(input: unknown): number {\n return JSON.stringify(input)\n .split(\"\")\n .reduce((a, b) => {\n a = (a << 5) - a + b.charCodeAt(0);\n return a & a;\n }, 0);\n}\n"],"mappings":"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","names":["useState","jsx","useState","use","useEffect","useState","relay","relay","useState","use","useEffect","loadQuery"]}