@remix-relay/react 2.4.4 → 2.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -48,12 +48,31 @@ var import_react_router = require("react-router");
48
48
  // src/deferred-query-context.tsx
49
49
  var import_react = require("react");
50
50
  var import_jsx_runtime = require("react/jsx-runtime");
51
- var DeferredQueryContext = (0, import_react.createContext)(void 0);
52
- var SetDeferredQueryContext = (0, import_react.createContext)(() => {
53
- });
51
+ function createDeferredQueryStore() {
52
+ let value = void 0;
53
+ const listeners = /* @__PURE__ */ new Set();
54
+ return {
55
+ get: () => value,
56
+ set: (newValue) => {
57
+ value = newValue;
58
+ listeners.forEach((l) => l());
59
+ },
60
+ subscribe: (listener) => {
61
+ listeners.add(listener);
62
+ return () => listeners.delete(listener);
63
+ }
64
+ };
65
+ }
66
+ var DeferredQueryStoreContext = (0, import_react.createContext)(
67
+ createDeferredQueryStore()
68
+ );
69
+ function useDeferredQuery() {
70
+ const store = (0, import_react.use)(DeferredQueryStoreContext);
71
+ return (0, import_react.useSyncExternalStore)(store.subscribe, store.get, () => void 0);
72
+ }
54
73
  function RemixRelayProvider({ children }) {
55
- const [deferredQueries, setDeferredQueries] = (0, import_react.useState)(void 0);
56
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SetDeferredQueryContext, { value: setDeferredQueries, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeferredQueryContext, { value: deferredQueries, children }) });
74
+ const store = (0, import_react.useMemo)(() => createDeferredQueryStore(), []);
75
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeferredQueryStoreContext, { value: store, children });
57
76
  }
58
77
 
59
78
  // src/Deferred.tsx
@@ -68,7 +87,7 @@ function useIsMounted() {
68
87
  }
69
88
  function Deferred({ children, ...rest }) {
70
89
  const mounted = useIsMounted();
71
- const deferredQuery = (0, import_react2.use)(DeferredQueryContext);
90
+ const deferredQuery = useDeferredQuery();
72
91
  if (!mounted || deferredQuery === void 0) {
73
92
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: rest.fallback });
74
93
  }
@@ -148,11 +167,16 @@ function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
148
167
  const preloadedQuery = "preloadedQuery" in loaderData ? loaderData.preloadedQuery : null;
149
168
  const deferredQueries = "deferredQueries" in loaderData ? loaderData.deferredQueries : null;
150
169
  const [deferredResult, setDeferredResult] = (0, import_react3.useState)(preloadedQuery);
151
- const setDeferredQueries = (0, import_react3.use)(SetDeferredQueryContext);
152
- (0, import_react3.useEffect)(() => {
170
+ const store = (0, import_react3.use)(DeferredQueryStoreContext);
171
+ const transformedPromiseRef = (0, import_react3.useRef)(null);
172
+ const prevDeferredQueriesRef = (0, import_react3.useRef)(
173
+ /* @__PURE__ */ Symbol()
174
+ );
175
+ if (deferredQueries !== prevDeferredQueriesRef.current) {
176
+ prevDeferredQueriesRef.current = deferredQueries;
153
177
  if (deferredQueries) {
154
- setDeferredQueries(
155
- deferredQueries.then(async (deferredResults) => {
178
+ transformedPromiseRef.current = deferredQueries.then(
179
+ async (deferredResults) => {
156
180
  deferredResults.forEach((result) => {
157
181
  (0, import_react_dom.flushSync)(() => {
158
182
  setDeferredResult(
@@ -161,12 +185,14 @@ function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
161
185
  });
162
186
  });
163
187
  return deferredResults;
164
- })
188
+ }
165
189
  );
190
+ store.set(transformedPromiseRef.current);
166
191
  } else {
167
- setDeferredQueries(null);
192
+ transformedPromiseRef.current = null;
193
+ store.set(null);
168
194
  }
169
- }, [deferredQueries, preloadedQuery, setDeferredQueries, setDeferredResult]);
195
+ }
170
196
  const environment = useRelayEnvironment();
171
197
  (0, import_react3.useMemo)(() => {
172
198
  if (deferredResult) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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":["export { Deferred } from \"./Deferred\";\nexport { clientLoaderQuery, getClientLoaderQuery } from \"./client-loader-query\";\nexport { RemixRelayProvider } from \"./deferred-query-context\";\nexport { getCachedResponse } from \"./get-cached-response\";\nexport { metaQuery } from \"./meta-query\";\nexport { useLoaderQuery, useRouteLoaderQuery } from \"./useLoaderQuery\";\n","import { Suspense, SuspenseProps, use, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { DeferredQueryContext } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = use(DeferredQueryContext);\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from \"react\";\nimport { createContext, useState } from \"react\";\n\nexport const DeferredQueryContext = createContext<\n Promise<unknown> | null | undefined\n>(undefined);\nexport const SetDeferredQueryContext = createContext<\n Dispatch<SetStateAction<Promise<unknown> | null | undefined>>\n>(() => {});\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const [deferredQueries, setDeferredQueries] = useState<\n Promise<unknown> | null | undefined\n >(undefined);\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","import 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 } else {\n setDeferredQueries(null);\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":["import_react","import_jsx_runtime","relay","import_react","import_react_relay","import_react_router","relay","invariant","loadQuery"]}
1
+ {"version":3,"sources":["../src/index.ts","../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":["export { Deferred } from \"./Deferred\";\nexport { clientLoaderQuery, getClientLoaderQuery } from \"./client-loader-query\";\nexport { RemixRelayProvider } from \"./deferred-query-context\";\nexport { getCachedResponse } from \"./get-cached-response\";\nexport { metaQuery } from \"./meta-query\";\nexport { useLoaderQuery, useRouteLoaderQuery } from \"./useLoaderQuery\";\n","import { Suspense, SuspenseProps, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { useDeferredQuery } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = useDeferredQuery();\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { PropsWithChildren } from \"react\";\nimport { createContext, use, useMemo, useSyncExternalStore } from \"react\";\n\ntype DeferredQueryValue = Promise<unknown> | null | undefined;\n\ntype DeferredQueryStore = {\n get: () => DeferredQueryValue;\n set: (value: DeferredQueryValue) => void;\n subscribe: (listener: () => void) => () => void;\n};\n\nfunction createDeferredQueryStore(): DeferredQueryStore {\n let value: DeferredQueryValue = undefined;\n const listeners = new Set<() => void>();\n\n return {\n get: () => value,\n set: (newValue) => {\n value = newValue;\n listeners.forEach((l) => l());\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nexport const DeferredQueryStoreContext = createContext<DeferredQueryStore>(\n createDeferredQueryStore(),\n);\n\nexport function useDeferredQuery(): DeferredQueryValue {\n const store = use(DeferredQueryStoreContext);\n return useSyncExternalStore(store.subscribe, store.get, () => undefined);\n}\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const store = useMemo(() => createDeferredQueryStore(), []);\n\n return (\n <DeferredQueryStoreContext value={store}>\n {children}\n </DeferredQueryStoreContext>\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","import 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, useMemo, useRef, 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 { DeferredQueryStoreContext } 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 store = use(DeferredQueryStoreContext);\n\n // Track transformed promise to avoid recreating on every render\n const transformedPromiseRef = useRef<Promise<unknown> | null>(null);\n const prevDeferredQueriesRef = useRef<typeof deferredQueries | symbol>(\n Symbol(),\n );\n\n // Set store synchronously during render (before Deferred reads it)\n if (deferredQueries !== prevDeferredQueriesRef.current) {\n prevDeferredQueriesRef.current = deferredQueries;\n if (deferredQueries) {\n transformedPromiseRef.current = deferredQueries.then(\n async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n return deferredResults;\n },\n );\n store.set(transformedPromiseRef.current);\n } else {\n transformedPromiseRef.current = null;\n store.set(null);\n }\n }\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":["import_react","import_jsx_runtime","relay","import_react","import_react_relay","import_react_router","relay","invariant","loadQuery"]}
package/dist/index.mjs CHANGED
@@ -1,22 +1,41 @@
1
1
  // src/Deferred.tsx
2
- import { Suspense, use, useSyncExternalStore } from "react";
2
+ import { Suspense, useSyncExternalStore as useSyncExternalStore2 } from "react";
3
3
  import { Await } from "react-router";
4
4
 
5
5
  // src/deferred-query-context.tsx
6
- import { createContext, useState } from "react";
6
+ import { createContext, use, useMemo, useSyncExternalStore } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
- var DeferredQueryContext = createContext(void 0);
9
- var SetDeferredQueryContext = createContext(() => {
10
- });
8
+ function createDeferredQueryStore() {
9
+ let value = void 0;
10
+ const listeners = /* @__PURE__ */ new Set();
11
+ return {
12
+ get: () => value,
13
+ set: (newValue) => {
14
+ value = newValue;
15
+ listeners.forEach((l) => l());
16
+ },
17
+ subscribe: (listener) => {
18
+ listeners.add(listener);
19
+ return () => listeners.delete(listener);
20
+ }
21
+ };
22
+ }
23
+ var DeferredQueryStoreContext = createContext(
24
+ createDeferredQueryStore()
25
+ );
26
+ function useDeferredQuery() {
27
+ const store = use(DeferredQueryStoreContext);
28
+ return useSyncExternalStore(store.subscribe, store.get, () => void 0);
29
+ }
11
30
  function RemixRelayProvider({ children }) {
12
- const [deferredQueries, setDeferredQueries] = useState(void 0);
13
- return /* @__PURE__ */ jsx(SetDeferredQueryContext, { value: setDeferredQueries, children: /* @__PURE__ */ jsx(DeferredQueryContext, { value: deferredQueries, children }) });
31
+ const store = useMemo(() => createDeferredQueryStore(), []);
32
+ return /* @__PURE__ */ jsx(DeferredQueryStoreContext, { value: store, children });
14
33
  }
15
34
 
16
35
  // src/Deferred.tsx
17
36
  import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
18
37
  function useIsMounted() {
19
- return useSyncExternalStore(
38
+ return useSyncExternalStore2(
20
39
  () => () => {
21
40
  },
22
41
  () => true,
@@ -25,7 +44,7 @@ function useIsMounted() {
25
44
  }
26
45
  function Deferred({ children, ...rest }) {
27
46
  const mounted = useIsMounted();
28
- const deferredQuery = use(DeferredQueryContext);
47
+ const deferredQuery = useDeferredQuery();
29
48
  if (!mounted || deferredQuery === void 0) {
30
49
  return /* @__PURE__ */ jsx2(Fragment, { children: rest.fallback });
31
50
  }
@@ -95,7 +114,7 @@ function metaQuery(metaFunction) {
95
114
  }
96
115
 
97
116
  // src/useLoaderQuery.ts
98
- import { use as use2, useEffect, useMemo, useState as useState2 } from "react";
117
+ import { use as use2, useMemo as useMemo2, useRef, useState } from "react";
99
118
  import { flushSync } from "react-dom";
100
119
  import relay2 from "react-relay";
101
120
  import { useLoaderData, useRouteLoaderData } from "react-router";
@@ -104,12 +123,17 @@ var { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay2;
104
123
  function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
105
124
  const preloadedQuery = "preloadedQuery" in loaderData ? loaderData.preloadedQuery : null;
106
125
  const deferredQueries = "deferredQueries" in loaderData ? loaderData.deferredQueries : null;
107
- const [deferredResult, setDeferredResult] = useState2(preloadedQuery);
108
- const setDeferredQueries = use2(SetDeferredQueryContext);
109
- useEffect(() => {
126
+ const [deferredResult, setDeferredResult] = useState(preloadedQuery);
127
+ const store = use2(DeferredQueryStoreContext);
128
+ const transformedPromiseRef = useRef(null);
129
+ const prevDeferredQueriesRef = useRef(
130
+ /* @__PURE__ */ Symbol()
131
+ );
132
+ if (deferredQueries !== prevDeferredQueriesRef.current) {
133
+ prevDeferredQueriesRef.current = deferredQueries;
110
134
  if (deferredQueries) {
111
- setDeferredQueries(
112
- deferredQueries.then(async (deferredResults) => {
135
+ transformedPromiseRef.current = deferredQueries.then(
136
+ async (deferredResults) => {
113
137
  deferredResults.forEach((result) => {
114
138
  flushSync(() => {
115
139
  setDeferredResult(
@@ -118,14 +142,16 @@ function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
118
142
  });
119
143
  });
120
144
  return deferredResults;
121
- })
145
+ }
122
146
  );
147
+ store.set(transformedPromiseRef.current);
123
148
  } else {
124
- setDeferredQueries(null);
149
+ transformedPromiseRef.current = null;
150
+ store.set(null);
125
151
  }
126
- }, [deferredQueries, preloadedQuery, setDeferredQueries, setDeferredResult]);
152
+ }
127
153
  const environment = useRelayEnvironment();
128
- useMemo(() => {
154
+ useMemo2(() => {
129
155
  if (deferredResult) {
130
156
  writePreloadedQueryToCache(deferredResult);
131
157
  }
@@ -1 +1 @@
1
- {"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, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { DeferredQueryContext } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = use(DeferredQueryContext);\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from \"react\";\nimport { createContext, useState } from \"react\";\n\nexport const DeferredQueryContext = createContext<\n Promise<unknown> | null | undefined\n>(undefined);\nexport const SetDeferredQueryContext = createContext<\n Dispatch<SetStateAction<Promise<unknown> | null | undefined>>\n>(() => {});\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const [deferredQueries, setDeferredQueries] = useState<\n Promise<unknown> | null | undefined\n >(undefined);\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","import 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 } else {\n setDeferredQueries(null);\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":["jsx","use","useState","relay","relay","useState","use","loadQuery"]}
1
+ {"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, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { useDeferredQuery } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = useDeferredQuery();\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { PropsWithChildren } from \"react\";\nimport { createContext, use, useMemo, useSyncExternalStore } from \"react\";\n\ntype DeferredQueryValue = Promise<unknown> | null | undefined;\n\ntype DeferredQueryStore = {\n get: () => DeferredQueryValue;\n set: (value: DeferredQueryValue) => void;\n subscribe: (listener: () => void) => () => void;\n};\n\nfunction createDeferredQueryStore(): DeferredQueryStore {\n let value: DeferredQueryValue = undefined;\n const listeners = new Set<() => void>();\n\n return {\n get: () => value,\n set: (newValue) => {\n value = newValue;\n listeners.forEach((l) => l());\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nexport const DeferredQueryStoreContext = createContext<DeferredQueryStore>(\n createDeferredQueryStore(),\n);\n\nexport function useDeferredQuery(): DeferredQueryValue {\n const store = use(DeferredQueryStoreContext);\n return useSyncExternalStore(store.subscribe, store.get, () => undefined);\n}\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const store = useMemo(() => createDeferredQueryStore(), []);\n\n return (\n <DeferredQueryStoreContext value={store}>\n {children}\n </DeferredQueryStoreContext>\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","import 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, useMemo, useRef, 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 { DeferredQueryStoreContext } 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 store = use(DeferredQueryStoreContext);\n\n // Track transformed promise to avoid recreating on every render\n const transformedPromiseRef = useRef<Promise<unknown> | null>(null);\n const prevDeferredQueriesRef = useRef<typeof deferredQueries | symbol>(\n Symbol(),\n );\n\n // Set store synchronously during render (before Deferred reads it)\n if (deferredQueries !== prevDeferredQueriesRef.current) {\n prevDeferredQueriesRef.current = deferredQueries;\n if (deferredQueries) {\n transformedPromiseRef.current = deferredQueries.then(\n async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n return deferredResults;\n },\n );\n store.set(transformedPromiseRef.current);\n } else {\n transformedPromiseRef.current = null;\n store.set(null);\n }\n }\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":["useSyncExternalStore","jsx","useSyncExternalStore","use","useMemo","relay","relay","use","useMemo","loadQuery"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-relay/react",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "description": "Provides Relay integration with React Router (Framework)",
5
5
  "keywords": [
6
6
  "Remix",