From ba2ed121e1f976d854d3044338beca9cc2887cc3 Mon Sep 17 00:00:00 2001
From: Tony Won <tony@daangn.com>
Date: Tue, 19 Nov 2024 15:57:31 +0900
Subject: [PATCH 1/2] WIP: add `useDeferredStack` flag in `stackflow()`
 initialization

---
 .../src/__internal__/core/CoreProvider.tsx    | 14 +++---------
 integrations/react/src/future/stackflow.tsx   | 17 +++++++++++++-
 integrations/react/src/stable/stackflow.tsx   | 22 ++++++++++++++++++-
 3 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/integrations/react/src/__internal__/core/CoreProvider.tsx b/integrations/react/src/__internal__/core/CoreProvider.tsx
index 565e5b59a..194381337 100644
--- a/integrations/react/src/__internal__/core/CoreProvider.tsx
+++ b/integrations/react/src/__internal__/core/CoreProvider.tsx
@@ -1,8 +1,6 @@
 import type { CoreStore, Stack } from "@stackflow/core";
 import { createContext } from "react";
 
-import { useDeferredValue, useSyncExternalStore } from "../shims";
-
 export const CoreActionsContext = createContext<CoreStore["actions"]>(
   null as any,
 );
@@ -10,22 +8,16 @@ export const CoreStateContext = createContext<Stack>(null as any);
 
 export interface CoreProviderProps {
   coreStore: CoreStore;
+  coreState: Stack;
   children: React.ReactNode;
 }
 export const CoreProvider: React.FC<CoreProviderProps> = ({
   coreStore,
+  coreState,
   children,
 }) => {
-  const stack = useSyncExternalStore(
-    coreStore.subscribe,
-    coreStore.actions.getStack,
-    coreStore.actions.getStack,
-  );
-
-  const deferredStack = useDeferredValue(stack);
-
   return (
-    <CoreStateContext.Provider value={deferredStack}>
+    <CoreStateContext.Provider value={coreState}>
       <CoreActionsContext.Provider value={coreStore.actions}>
         {children}
       </CoreActionsContext.Provider>
diff --git a/integrations/react/src/future/stackflow.tsx b/integrations/react/src/future/stackflow.tsx
index 47abcd78b..94f3b182f 100644
--- a/integrations/react/src/future/stackflow.tsx
+++ b/integrations/react/src/future/stackflow.tsx
@@ -14,6 +14,7 @@ import MainRenderer from "../__internal__/MainRenderer";
 import { makeActivityId } from "../__internal__/activity";
 import { CoreProvider } from "../__internal__/core";
 import { PluginsProvider } from "../__internal__/plugins";
+import { useDeferredValue, useSyncExternalStore } from "../__internal__/shims";
 import { isBrowser, makeRef } from "../__internal__/utils";
 import type { ActivityComponentType, StackflowReactPlugin } from "../stable";
 import type { Actions } from "./Actions";
@@ -37,6 +38,7 @@ export type StackflowInput<
   config: Config<T>;
   components: R;
   plugins?: Array<StackflowPluginsEntry>;
+  useDeferredStack?: boolean;
 };
 
 export type StackflowOutput = {
@@ -62,6 +64,8 @@ export function stackflow<
     loaderPlugin(input.config),
   ];
 
+  const useDeferredStack = input.useDeferredStack ?? true;
+
   const enoughPastTime = () =>
     new Date().getTime() - input.config.transitionDuration * 2;
 
@@ -154,10 +158,21 @@ export function stackflow<
       return store;
     }, []);
 
+    const coreState = useSyncExternalStore(
+      coreStore.subscribe,
+      coreStore.actions.getStack,
+      coreStore.actions.getStack,
+    );
+
+    const deferredCoreState = useDeferredValue(coreState);
+
     return (
       <ConfigProvider value={input.config}>
         <PluginsProvider value={coreStore.pluginInstances}>
-          <CoreProvider coreStore={coreStore}>
+          <CoreProvider
+            coreState={useDeferredStack ? deferredCoreState : coreState}
+            coreStore={coreStore}
+          >
             <MainRenderer
               activityComponentMap={input.components}
               initialContext={initialContext}
diff --git a/integrations/react/src/stable/stackflow.tsx b/integrations/react/src/stable/stackflow.tsx
index 85b69d4fd..27fad60ac 100644
--- a/integrations/react/src/stable/stackflow.tsx
+++ b/integrations/react/src/stable/stackflow.tsx
@@ -14,6 +14,7 @@ import type { StackflowReactPlugin } from "../__internal__/StackflowReactPlugin"
 import { makeActivityId, makeStepId } from "../__internal__/activity";
 import { CoreProvider } from "../__internal__/core";
 import { PluginsProvider } from "../__internal__/plugins";
+import { useDeferredValue, useSyncExternalStore } from "../__internal__/shims";
 import { isBrowser, makeRef } from "../__internal__/utils";
 import type { BaseActivities } from "./BaseActivities";
 import type { UseActionsOutputType } from "./useActions";
@@ -69,6 +70,12 @@ export type StackflowOptions<T extends BaseActivities> = {
    * Inject stackflow plugins
    */
   plugins?: Array<StackflowPluginsEntry<NoInfer<T>>>;
+
+  /**
+   * Render stack state with `useDeferredValue()` (concurrent rendering)
+   * https://react.dev/reference/react/useDeferredValue
+   */
+  useDeferredStack?: boolean;
 };
 
 export type StackflowOutput<T extends BaseActivities> = {
@@ -135,6 +142,8 @@ export function stackflow<T extends BaseActivities>(
     },
   );
 
+  const useDeferredStack = options.useDeferredStack ?? true;
+
   const enoughPastTime = () =>
     new Date().getTime() - options.transitionDuration * 2;
 
@@ -218,9 +227,20 @@ export function stackflow<T extends BaseActivities>(
       return store;
     }, []);
 
+    const coreState = useSyncExternalStore(
+      coreStore.subscribe,
+      coreStore.actions.getStack,
+      coreStore.actions.getStack,
+    );
+
+    const deferredCoreState = useDeferredValue(coreState);
+
     return (
       <PluginsProvider value={coreStore.pluginInstances}>
-        <CoreProvider coreStore={coreStore}>
+        <CoreProvider
+          coreStore={coreStore}
+          coreState={useDeferredStack ? deferredCoreState : coreState}
+        >
           <MainRenderer
             activityComponentMap={activityComponentMap}
             initialContext={props.initialContext}

From ea5f499b60e6edbe96629e6a1bfcdb1342d9cc5b Mon Sep 17 00:00:00 2001
From: Tony Won <tony@daangn.com>
Date: Mon, 2 Dec 2024 11:31:27 +0900
Subject: [PATCH 2/2] changeset

---
 .changeset/honest-gorillas-pretend.md | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 .changeset/honest-gorillas-pretend.md

diff --git a/.changeset/honest-gorillas-pretend.md b/.changeset/honest-gorillas-pretend.md
new file mode 100644
index 000000000..ed28ceec4
--- /dev/null
+++ b/.changeset/honest-gorillas-pretend.md
@@ -0,0 +1,5 @@
+---
+"@stackflow/react": patch
+---
+
+feat(react): Add option `useDeferredStack` to disable use of `useDeferredValue`