diff --git a/packages/effect-fc/src/Component.ts b/packages/effect-fc/src/Component.ts index a407b54..b367240 100644 --- a/packages/effect-fc/src/Component.ts +++ b/packages/effect-fc/src/Component.ts @@ -99,9 +99,18 @@ export const useSuspenseFC: { const scope = Runtime.runSync(runtimeRef.current)(Hook.useScope([], self.options)) const FC = React.useMemo(() => { - const f = (props: P) => Runtime.runSync(runtimeRef.current)( - Effect.provideService(self(props), Scope.Scope, scope) - ) + const inner = (props: { readonly promise: Promise }) => React.use(props.promise) + + const f = React.memo((props: P) => { + const promise = Runtime.runPromise(runtimeRef.current)( + Effect.provideService(self(props), Scope.Scope, scope) + ) + return React.createElement( + React.Suspense, + { fallback: "Loading..." }, + React.createElement(inner, { promise }), + ) + }) f.displayName = self.displayName ?? "Anonymous" return f }, [scope]) diff --git a/packages/example/src/routeTree.gen.ts b/packages/example/src/routeTree.gen.ts index 87e976f..544cf65 100644 --- a/packages/example/src/routeTree.gen.ts +++ b/packages/example/src/routeTree.gen.ts @@ -10,6 +10,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as BlankRouteImport } from './routes/blank' +import { Route as AsyncRenderingRouteImport } from './routes/async-rendering' import { Route as IndexRouteImport } from './routes/index' const BlankRoute = BlankRouteImport.update({ @@ -17,6 +18,11 @@ const BlankRoute = BlankRouteImport.update({ path: '/blank', getParentRoute: () => rootRouteImport, } as any) +const AsyncRenderingRoute = AsyncRenderingRouteImport.update({ + id: '/async-rendering', + path: '/async-rendering', + getParentRoute: () => rootRouteImport, +} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', @@ -25,27 +31,31 @@ const IndexRoute = IndexRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute + '/async-rendering': typeof AsyncRenderingRoute '/blank': typeof BlankRoute } export interface FileRoutesByTo { '/': typeof IndexRoute + '/async-rendering': typeof AsyncRenderingRoute '/blank': typeof BlankRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute + '/async-rendering': typeof AsyncRenderingRoute '/blank': typeof BlankRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/blank' + fullPaths: '/' | '/async-rendering' | '/blank' fileRoutesByTo: FileRoutesByTo - to: '/' | '/blank' - id: '__root__' | '/' | '/blank' + to: '/' | '/async-rendering' | '/blank' + id: '__root__' | '/' | '/async-rendering' | '/blank' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + AsyncRenderingRoute: typeof AsyncRenderingRoute BlankRoute: typeof BlankRoute } @@ -58,6 +68,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof BlankRouteImport parentRoute: typeof rootRouteImport } + '/async-rendering': { + id: '/async-rendering' + path: '/async-rendering' + fullPath: '/async-rendering' + preLoaderRoute: typeof AsyncRenderingRouteImport + parentRoute: typeof rootRouteImport + } '/': { id: '/' path: '/' @@ -70,6 +87,7 @@ declare module '@tanstack/react-router' { const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + AsyncRenderingRoute: AsyncRenderingRoute, BlankRoute: BlankRoute, } export const routeTree = rootRouteImport diff --git a/packages/example/src/routes/async-rendering.tsx b/packages/example/src/routes/async-rendering.tsx new file mode 100644 index 0000000..685c30d --- /dev/null +++ b/packages/example/src/routes/async-rendering.tsx @@ -0,0 +1,28 @@ +import { runtime } from "@/runtime" +import { Text } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Console, Effect } from "effect" +import { Component } from "effect-fc" + + +const RouteComponent = Component.make(function* AsyncRendering() { + console.log("render") + const VAsyncComponent = yield* Component.useSuspenseFC(AsyncComponent) + return <> + Route component + + +}).pipe( + Component.withRuntime(runtime.context) +) + +const AsyncComponent = Component.make(function* AsyncComponent() { + yield* Console.log("rendering") + yield* Effect.sleep("500 millis") + return Rendered! +}) + + +export const Route = createFileRoute("/async-rendering")({ + component: RouteComponent +})