From 78258ca2b3f6cfc67a75e4e6099971ff18abde0f Mon Sep 17 00:00:00 2001 From: ENvironmentSet Date: Thu, 30 Jul 2026 16:35:34 +0900 Subject: [PATCH 1/3] fix(react): keep loader results out of snapshots (FEP-2613) --- .../fep-2613-loader-result-reference.md | 5 + .../react/src/loader/LoaderResultContext.tsx | 24 +++ .../react/src/loader/loaderPlugin.tsx | 191 +++++++++++++----- .../react/src/loader/useLoaderData.ts | 6 +- 4 files changed, 172 insertions(+), 54 deletions(-) create mode 100644 .changeset/fep-2613-loader-result-reference.md create mode 100644 integrations/react/src/loader/LoaderResultContext.tsx diff --git a/.changeset/fep-2613-loader-result-reference.md b/.changeset/fep-2613-loader-result-reference.md new file mode 100644 index 000000000..f0b91578f --- /dev/null +++ b/.changeset/fep-2613-loader-result-reference.md @@ -0,0 +1,5 @@ +--- +"@stackflow/react": patch +--- + +Keep loader results out of navigation snapshots by storing opaque references in activity context and resolving them within the React loader plugin. diff --git a/integrations/react/src/loader/LoaderResultContext.tsx b/integrations/react/src/loader/LoaderResultContext.tsx new file mode 100644 index 000000000..491fca24f --- /dev/null +++ b/integrations/react/src/loader/LoaderResultContext.tsx @@ -0,0 +1,24 @@ +import { createContext, type ReactNode, useContext } from "react"; +import type { SyncInspectablePromise } from "../utils/SyncInspectablePromise"; + +const LoaderResultContext = createContext< + SyncInspectablePromise | undefined +>(undefined); + +export function LoaderResultProvider({ + loaderResultPromise, + children, +}: { + loaderResultPromise: SyncInspectablePromise | undefined; + children: ReactNode; +}) { + return ( + + {children} + + ); +} + +export function useLoaderResultPromise() { + return useContext(LoaderResultContext); +} diff --git a/integrations/react/src/loader/loaderPlugin.tsx b/integrations/react/src/loader/loaderPlugin.tsx index a06623cfe..b0de35c01 100644 --- a/integrations/react/src/loader/loaderPlugin.tsx +++ b/integrations/react/src/loader/loaderPlugin.tsx @@ -2,7 +2,7 @@ import type { ActivityDefinition, RegisteredActivityName, } from "@stackflow/config"; -import type { Stack } from "@stackflow/core"; +import { id, type Stack } from "@stackflow/core"; import type { ActivityComponentType } from "../BaseActivityComponentType"; import type { StackflowReactPlugin } from "../StackflowReactPlugin"; import { @@ -10,15 +10,50 @@ import { isStructuredActivityComponent, } from "../StructuredActivityComponentType"; import type { StackflowInput } from "../stackflow"; +import { LoaderResultProvider } from "./LoaderResultContext"; import { defer, inspect, PromiseStatus, resolve, - type SyncInspectableDeferred, type SyncInspectablePromise, } from "../utils/SyncInspectablePromise"; +const LOADER_RESULT_ID_KEY = "@stackflow/react/loaderResultId"; + +type LoaderResultId = string; + +type LoaderResultEntry = { + promise: SyncInspectablePromise; + start?: (load: () => unknown) => boolean; +}; + +function getLoaderResultId( + activityContext: unknown, +): LoaderResultId | undefined { + if (typeof activityContext !== "object" || activityContext === null) { + return undefined; + } + + const loaderResultId = (activityContext as Record)[ + LOADER_RESULT_ID_KEY + ]; + + return typeof loaderResultId === "string" ? loaderResultId : undefined; +} + +function withLoaderResultId( + activityContext: unknown, + loaderResultId: LoaderResultId, +) { + return { + ...(typeof activityContext === "object" && activityContext !== null + ? activityContext + : {}), + [LOADER_RESULT_ID_KEY]: loaderResultId, + }; +} + export function loaderPlugin< T extends ActivityDefinition, R extends { @@ -29,45 +64,73 @@ export function loaderPlugin< loadData: (activityName: string, activityParams: {}) => unknown, ): StackflowReactPlugin { return () => { - const loadPathDeferreds = new WeakMap< - SyncInspectablePromise, - SyncInspectableDeferred - >(); + const loaderResults = new Map(); + + const addLoaderResult = (promise: SyncInspectablePromise) => { + const loaderResultId = id(); + loaderResults.set(loaderResultId, { promise }); + return loaderResultId; + }; + + const addDeferredLoaderResult = () => { + const loaderData = defer(); + let started = false; + const loaderResultId = id(); + + loaderResults.set(loaderResultId, { + promise: loaderData.promise, + start(load) { + if (started) { + return false; + } + + started = true; + + try { + loaderData.resolve(load()); + } catch (error) { + loaderData.reject(error); + } + + return true; + }, + }); + + return loaderResultId; + }; const resolveDeferredLoaderData = ({ activityName, activityParams, - loaderData, + loaderResultId, }: { activityName: string; activityParams: {}; - loaderData: SyncInspectablePromise | undefined; + loaderResultId: LoaderResultId | undefined; }) => { const matchActivity = input.config.activities.find( (candidate) => candidate.name === activityName, ); - const deferred = loaderData - ? loadPathDeferreds.get(loaderData) + const loaderResult = loaderResultId + ? loaderResults.get(loaderResultId) : undefined; - if (!matchActivity?.loader || !loaderData || !deferred) { + if (!matchActivity?.loader || !loaderResult?.start) { return; } - loadPathDeferreds.delete(loaderData); - - Promise.allSettled([loaderData]).then(([loaderDataPromiseResult]) => { - printLoaderDataPromiseError({ - promiseResult: loaderDataPromiseResult, - activityName: matchActivity.name, - }); - }); - - try { - deferred.resolve(loadData(activityName, activityParams)); - } catch (error) { - deferred.reject(error); + if (!loaderResult.start(() => loadData(activityName, activityParams))) { + return; } + + Promise.allSettled([loaderResult.promise]).then( + ([loaderDataPromiseResult]) => { + printLoaderDataPromiseError({ + promiseResult: loaderDataPromiseResult, + activityName: matchActivity.name, + }); + }, + ); }; const resolveRestoredStackLoaderData = (stack: Stack) => { @@ -77,7 +140,7 @@ export function loaderPlugin< resolveDeferredLoaderData({ activityName: activity.name, activityParams: activity.params, - loaderData: (activity.context as any)?.loaderData, + loaderResultId: getLoaderResultId(activity.context), }); }); }; @@ -93,7 +156,7 @@ export function loaderPlugin< resolveDeferredLoaderData({ activityName: event.activityName, activityParams: event.activityParams, - loaderData: (event.activityContext as any)?.loaderData, + loaderResultId: getLoaderResultId(event.activityContext), }); }); }; @@ -119,15 +182,14 @@ export function loaderPlugin< return event; } - const loaderData = defer(); - loadPathDeferreds.set(loaderData.promise, loaderData); + const loaderResultId = addDeferredLoaderResult(); return { ...event, - activityContext: { - ...event.activityContext, - loaderData: loaderData.promise, - }, + activityContext: withLoaderResultId( + event.activityContext, + loaderResultId, + ), }; }); } @@ -137,16 +199,6 @@ export function loaderPlugin< return event; } - if (initialContext.initialLoaderData) { - return { - ...event, - activityContext: { - ...event.activityContext, - loaderData: resolve(initialContext.initialLoaderData), - }, - }; - } - const { activityName, activityParams } = event; const matchActivity = input.config.activities.find( @@ -159,7 +211,22 @@ export function loaderPlugin< return event; } + if (initialContext.initialLoaderData) { + const loaderResultId = addLoaderResult( + resolve(initialContext.initialLoaderData), + ); + + return { + ...event, + activityContext: withLoaderResultId( + event.activityContext, + loaderResultId, + ), + }; + } + const loaderData = resolve(loadData(activityName, activityParams)); + const loaderResultId = addLoaderResult(loaderData); Promise.allSettled([loaderData]).then(([loaderDataPromiseResult]) => { printLoaderDataPromiseError({ @@ -170,10 +237,10 @@ export function loaderPlugin< return { ...event, - activityContext: { - ...event.activityContext, - loaderData, - }, + activityContext: withLoaderResultId( + event.activityContext, + loaderResultId, + ), }; }); }, @@ -186,8 +253,24 @@ export function loaderPlugin< resolveRestoredStackLoaderData(stack); resolvePausedEventLoaderData(stack.pausedEvents); }, - onBeforePush: createBeforeRouteHandler(input, loadData), - onBeforeReplace: createBeforeRouteHandler(input, loadData), + onBeforePush: createBeforeRouteHandler(input, loadData, addLoaderResult), + onBeforeReplace: createBeforeRouteHandler( + input, + loadData, + addLoaderResult, + ), + wrapActivity({ activity }) { + const loaderResultId = getLoaderResultId(activity.context); + const loaderResultPromise = loaderResultId + ? loaderResults.get(loaderResultId)?.promise + : undefined; + + return ( + + {activity.render()} + + ); + }, }; }; } @@ -205,6 +288,7 @@ function createBeforeRouteHandler< >( input: StackflowInput, loadData: (activityName: string, activityParams: {}) => unknown, + addLoaderResult: (promise: SyncInspectablePromise) => LoaderResultId, ): OnBeforeRoute { return ({ actionParams, actions }) => { if (actions.isPrevented()) { @@ -261,12 +345,15 @@ function createBeforeRouteHandler< }); } + if (!loaderData) { + return; + } + + const loaderResultId = addLoaderResult(loaderData); + overrideActionParams({ ...actionParams, - activityContext: { - ...activityContext, - loaderData, - }, + activityContext: withLoaderResultId(activityContext, loaderResultId), }); }; } diff --git a/integrations/react/src/loader/useLoaderData.ts b/integrations/react/src/loader/useLoaderData.ts index f7c13944a..234bf0e58 100644 --- a/integrations/react/src/loader/useLoaderData.ts +++ b/integrations/react/src/loader/useLoaderData.ts @@ -1,10 +1,12 @@ import type { ActivityLoaderArgs } from "@stackflow/config"; import { resolve } from "../utils/SyncInspectablePromise"; import { useThenable } from "../utils/useThenable"; -import { useActivity } from "../activity/useActivity"; +import { useLoaderResultPromise } from "./LoaderResultContext"; export function useLoaderData< T extends (args: ActivityLoaderArgs) => any, >(): Awaited> { - return useThenable(resolve((useActivity().context as any)?.loaderData)); + return useThenable(resolve(useLoaderResultPromise())) as Awaited< + ReturnType + >; } From 203edbf65906b158463ed28d9831e7fe65a84fc7 Mon Sep 17 00:00:00 2001 From: ENvironmentSet Date: Thu, 30 Jul 2026 16:42:31 +0900 Subject: [PATCH 2/3] refactor(react): simplify loader result context --- .../react/src/loader/LoaderResultContext.tsx | 22 ++----------------- .../react/src/loader/loaderPlugin.tsx | 19 +++++++++++----- .../react/src/loader/useLoaderData.ts | 5 +++-- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/integrations/react/src/loader/LoaderResultContext.tsx b/integrations/react/src/loader/LoaderResultContext.tsx index 491fca24f..c7aba1a1a 100644 --- a/integrations/react/src/loader/LoaderResultContext.tsx +++ b/integrations/react/src/loader/LoaderResultContext.tsx @@ -1,24 +1,6 @@ -import { createContext, type ReactNode, useContext } from "react"; +import { createContext } from "react"; import type { SyncInspectablePromise } from "../utils/SyncInspectablePromise"; -const LoaderResultContext = createContext< +export const LoaderResultContext = createContext< SyncInspectablePromise | undefined >(undefined); - -export function LoaderResultProvider({ - loaderResultPromise, - children, -}: { - loaderResultPromise: SyncInspectablePromise | undefined; - children: ReactNode; -}) { - return ( - - {children} - - ); -} - -export function useLoaderResultPromise() { - return useContext(LoaderResultContext); -} diff --git a/integrations/react/src/loader/loaderPlugin.tsx b/integrations/react/src/loader/loaderPlugin.tsx index b0de35c01..987861cbf 100644 --- a/integrations/react/src/loader/loaderPlugin.tsx +++ b/integrations/react/src/loader/loaderPlugin.tsx @@ -2,7 +2,7 @@ import type { ActivityDefinition, RegisteredActivityName, } from "@stackflow/config"; -import { id, type Stack } from "@stackflow/core"; +import type { Stack } from "@stackflow/core"; import type { ActivityComponentType } from "../BaseActivityComponentType"; import type { StackflowReactPlugin } from "../StackflowReactPlugin"; import { @@ -10,7 +10,7 @@ import { isStructuredActivityComponent, } from "../StructuredActivityComponentType"; import type { StackflowInput } from "../stackflow"; -import { LoaderResultProvider } from "./LoaderResultContext"; +import { LoaderResultContext } from "./LoaderResultContext"; import { defer, inspect, @@ -28,6 +28,13 @@ type LoaderResultEntry = { start?: (load: () => unknown) => boolean; }; +let nextLoaderResultId = 0; + +function makeLoaderResultId(): LoaderResultId { + nextLoaderResultId += 1; + return nextLoaderResultId.toString(); +} + function getLoaderResultId( activityContext: unknown, ): LoaderResultId | undefined { @@ -67,7 +74,7 @@ export function loaderPlugin< const loaderResults = new Map(); const addLoaderResult = (promise: SyncInspectablePromise) => { - const loaderResultId = id(); + const loaderResultId = makeLoaderResultId(); loaderResults.set(loaderResultId, { promise }); return loaderResultId; }; @@ -75,7 +82,7 @@ export function loaderPlugin< const addDeferredLoaderResult = () => { const loaderData = defer(); let started = false; - const loaderResultId = id(); + const loaderResultId = makeLoaderResultId(); loaderResults.set(loaderResultId, { promise: loaderData.promise, @@ -266,9 +273,9 @@ export function loaderPlugin< : undefined; return ( - + {activity.render()} - + ); }, }; diff --git a/integrations/react/src/loader/useLoaderData.ts b/integrations/react/src/loader/useLoaderData.ts index 234bf0e58..001121678 100644 --- a/integrations/react/src/loader/useLoaderData.ts +++ b/integrations/react/src/loader/useLoaderData.ts @@ -1,12 +1,13 @@ import type { ActivityLoaderArgs } from "@stackflow/config"; +import { useContext } from "react"; import { resolve } from "../utils/SyncInspectablePromise"; import { useThenable } from "../utils/useThenable"; -import { useLoaderResultPromise } from "./LoaderResultContext"; +import { LoaderResultContext } from "./LoaderResultContext"; export function useLoaderData< T extends (args: ActivityLoaderArgs) => any, >(): Awaited> { - return useThenable(resolve(useLoaderResultPromise())) as Awaited< + return useThenable(resolve(useContext(LoaderResultContext))) as Awaited< ReturnType >; } From 0c56baa3e131e101371b485f16ca20236dc7d5e9 Mon Sep 17 00:00:00 2001 From: ENvironmentSet Date: Thu, 30 Jul 2026 17:02:45 +0900 Subject: [PATCH 3/3] refactor(react): centralize loader result state --- .../react/src/loader/LoaderResultStore.ts | 94 +++++++++++ .../react/src/loader/loaderPlugin.tsx | 146 +++++------------- 2 files changed, 131 insertions(+), 109 deletions(-) create mode 100644 integrations/react/src/loader/LoaderResultStore.ts diff --git a/integrations/react/src/loader/LoaderResultStore.ts b/integrations/react/src/loader/LoaderResultStore.ts new file mode 100644 index 000000000..b7779de33 --- /dev/null +++ b/integrations/react/src/loader/LoaderResultStore.ts @@ -0,0 +1,94 @@ +import { + defer, + type SyncInspectablePromise, +} from "../utils/SyncInspectablePromise"; + +const LOADER_RESULT_ID_KEY = "@stackflow/react/loaderResultId"; + +export type LoaderResultId = string; + +type LoaderResultEntry = { + promise: SyncInspectablePromise; + start?: (load: () => unknown) => boolean; +}; + +let nextLoaderResultId = 0; + +export class LoaderResultStore { + private readonly entries = new Map(); + + add(promise: SyncInspectablePromise): LoaderResultId { + const loaderResultId = makeLoaderResultId(); + this.entries.set(loaderResultId, { promise }); + return loaderResultId; + } + + addDeferred(): LoaderResultId { + const loaderData = defer(); + let started = false; + const loaderResultId = makeLoaderResultId(); + + this.entries.set(loaderResultId, { + promise: loaderData.promise, + start(load) { + if (started) { + return false; + } + + started = true; + + try { + loaderData.resolve(load()); + } catch (error) { + loaderData.reject(error); + } + + return true; + }, + }); + + return loaderResultId; + } + + get(loaderResultId: LoaderResultId | undefined) { + return loaderResultId + ? this.entries.get(loaderResultId)?.promise + : undefined; + } + + start(loaderResultId: LoaderResultId, load: () => unknown) { + const entry = this.entries.get(loaderResultId); + + if (!entry?.start || !entry.start(load)) { + return undefined; + } + + return entry.promise; + } + + getId(activityContext: unknown): LoaderResultId | undefined { + if (typeof activityContext !== "object" || activityContext === null) { + return undefined; + } + + const loaderResultId = (activityContext as Record)[ + LOADER_RESULT_ID_KEY + ]; + + return typeof loaderResultId === "string" ? loaderResultId : undefined; + } + + withId(activityContext: unknown, loaderResultId: LoaderResultId) { + return { + ...(typeof activityContext === "object" && activityContext !== null + ? activityContext + : {}), + [LOADER_RESULT_ID_KEY]: loaderResultId, + }; + } +} + +function makeLoaderResultId(): LoaderResultId { + nextLoaderResultId += 1; + return nextLoaderResultId.toString(); +} diff --git a/integrations/react/src/loader/loaderPlugin.tsx b/integrations/react/src/loader/loaderPlugin.tsx index 987861cbf..00e2037cd 100644 --- a/integrations/react/src/loader/loaderPlugin.tsx +++ b/integrations/react/src/loader/loaderPlugin.tsx @@ -11,56 +11,13 @@ import { } from "../StructuredActivityComponentType"; import type { StackflowInput } from "../stackflow"; import { LoaderResultContext } from "./LoaderResultContext"; +import { LoaderResultStore, type LoaderResultId } from "./LoaderResultStore"; import { - defer, inspect, PromiseStatus, resolve, - type SyncInspectablePromise, } from "../utils/SyncInspectablePromise"; -const LOADER_RESULT_ID_KEY = "@stackflow/react/loaderResultId"; - -type LoaderResultId = string; - -type LoaderResultEntry = { - promise: SyncInspectablePromise; - start?: (load: () => unknown) => boolean; -}; - -let nextLoaderResultId = 0; - -function makeLoaderResultId(): LoaderResultId { - nextLoaderResultId += 1; - return nextLoaderResultId.toString(); -} - -function getLoaderResultId( - activityContext: unknown, -): LoaderResultId | undefined { - if (typeof activityContext !== "object" || activityContext === null) { - return undefined; - } - - const loaderResultId = (activityContext as Record)[ - LOADER_RESULT_ID_KEY - ]; - - return typeof loaderResultId === "string" ? loaderResultId : undefined; -} - -function withLoaderResultId( - activityContext: unknown, - loaderResultId: LoaderResultId, -) { - return { - ...(typeof activityContext === "object" && activityContext !== null - ? activityContext - : {}), - [LOADER_RESULT_ID_KEY]: loaderResultId, - }; -} - export function loaderPlugin< T extends ActivityDefinition, R extends { @@ -71,40 +28,7 @@ export function loaderPlugin< loadData: (activityName: string, activityParams: {}) => unknown, ): StackflowReactPlugin { return () => { - const loaderResults = new Map(); - - const addLoaderResult = (promise: SyncInspectablePromise) => { - const loaderResultId = makeLoaderResultId(); - loaderResults.set(loaderResultId, { promise }); - return loaderResultId; - }; - - const addDeferredLoaderResult = () => { - const loaderData = defer(); - let started = false; - const loaderResultId = makeLoaderResultId(); - - loaderResults.set(loaderResultId, { - promise: loaderData.promise, - start(load) { - if (started) { - return false; - } - - started = true; - - try { - loaderData.resolve(load()); - } catch (error) { - loaderData.reject(error); - } - - return true; - }, - }); - - return loaderResultId; - }; + const loaderResultStore = new LoaderResultStore(); const resolveDeferredLoaderData = ({ activityName, @@ -118,26 +42,24 @@ export function loaderPlugin< const matchActivity = input.config.activities.find( (candidate) => candidate.name === activityName, ); - const loaderResult = loaderResultId - ? loaderResults.get(loaderResultId) - : undefined; - - if (!matchActivity?.loader || !loaderResult?.start) { + if (!matchActivity?.loader || !loaderResultId) { return; } - if (!loaderResult.start(() => loadData(activityName, activityParams))) { + const loaderData = loaderResultStore.start(loaderResultId, () => + loadData(activityName, activityParams), + ); + + if (!loaderData) { return; } - Promise.allSettled([loaderResult.promise]).then( - ([loaderDataPromiseResult]) => { - printLoaderDataPromiseError({ - promiseResult: loaderDataPromiseResult, - activityName: matchActivity.name, - }); - }, - ); + Promise.allSettled([loaderData]).then(([loaderDataPromiseResult]) => { + printLoaderDataPromiseError({ + promiseResult: loaderDataPromiseResult, + activityName: matchActivity.name, + }); + }); }; const resolveRestoredStackLoaderData = (stack: Stack) => { @@ -147,7 +69,7 @@ export function loaderPlugin< resolveDeferredLoaderData({ activityName: activity.name, activityParams: activity.params, - loaderResultId: getLoaderResultId(activity.context), + loaderResultId: loaderResultStore.getId(activity.context), }); }); }; @@ -163,7 +85,7 @@ export function loaderPlugin< resolveDeferredLoaderData({ activityName: event.activityName, activityParams: event.activityParams, - loaderResultId: getLoaderResultId(event.activityContext), + loaderResultId: loaderResultStore.getId(event.activityContext), }); }); }; @@ -189,11 +111,11 @@ export function loaderPlugin< return event; } - const loaderResultId = addDeferredLoaderResult(); + const loaderResultId = loaderResultStore.addDeferred(); return { ...event, - activityContext: withLoaderResultId( + activityContext: loaderResultStore.withId( event.activityContext, loaderResultId, ), @@ -219,13 +141,13 @@ export function loaderPlugin< } if (initialContext.initialLoaderData) { - const loaderResultId = addLoaderResult( + const loaderResultId = loaderResultStore.add( resolve(initialContext.initialLoaderData), ); return { ...event, - activityContext: withLoaderResultId( + activityContext: loaderResultStore.withId( event.activityContext, loaderResultId, ), @@ -233,7 +155,7 @@ export function loaderPlugin< } const loaderData = resolve(loadData(activityName, activityParams)); - const loaderResultId = addLoaderResult(loaderData); + const loaderResultId = loaderResultStore.add(loaderData); Promise.allSettled([loaderData]).then(([loaderDataPromiseResult]) => { printLoaderDataPromiseError({ @@ -244,7 +166,7 @@ export function loaderPlugin< return { ...event, - activityContext: withLoaderResultId( + activityContext: loaderResultStore.withId( event.activityContext, loaderResultId, ), @@ -260,17 +182,20 @@ export function loaderPlugin< resolveRestoredStackLoaderData(stack); resolvePausedEventLoaderData(stack.pausedEvents); }, - onBeforePush: createBeforeRouteHandler(input, loadData, addLoaderResult), + onBeforePush: createBeforeRouteHandler( + input, + loadData, + loaderResultStore, + ), onBeforeReplace: createBeforeRouteHandler( input, loadData, - addLoaderResult, + loaderResultStore, ), wrapActivity({ activity }) { - const loaderResultId = getLoaderResultId(activity.context); - const loaderResultPromise = loaderResultId - ? loaderResults.get(loaderResultId)?.promise - : undefined; + const loaderResultPromise = loaderResultStore.get( + loaderResultStore.getId(activity.context), + ); return ( @@ -295,7 +220,7 @@ function createBeforeRouteHandler< >( input: StackflowInput, loadData: (activityName: string, activityParams: {}) => unknown, - addLoaderResult: (promise: SyncInspectablePromise) => LoaderResultId, + loaderResultStore: LoaderResultStore, ): OnBeforeRoute { return ({ actionParams, actions }) => { if (actions.isPrevented()) { @@ -356,11 +281,14 @@ function createBeforeRouteHandler< return; } - const loaderResultId = addLoaderResult(loaderData); + const loaderResultId = loaderResultStore.add(loaderData); overrideActionParams({ ...actionParams, - activityContext: withLoaderResultId(activityContext, loaderResultId), + activityContext: loaderResultStore.withId( + activityContext, + loaderResultId, + ), }); }; }