From 0619af652473c33e597dc498eb5fe907c0721611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 30 Oct 2025 14:36:47 +0100 Subject: [PATCH] Fix --- packages/effect-fc/src/Component.ts | 8 ++--- packages/example/src/routeTree.gen.ts | 21 ++++++++++++ packages/example/src/routes/result.tsx | 44 ++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 packages/example/src/routes/result.tsx diff --git a/packages/effect-fc/src/Component.ts b/packages/effect-fc/src/Component.ts index ed24655..8694fff 100644 --- a/packages/effect-fc/src/Component.ts +++ b/packages/effect-fc/src/Component.ts @@ -1,6 +1,6 @@ /** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */ /** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ -import { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Stream, Tracer, type Types, type Utils } from "effect" +import { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Stream, Tracer, type Utils } from "effect" import * as React from "react" import { Memoized } from "./index.js" import * as Result from "./Result.js" @@ -387,9 +387,9 @@ export const withOptions: { export const withRuntime: {

( context: React.Context>, - ): (self: Component>) => (props: P) => A + ): (self: Component>) => (props: P) => A

( - self: Component>, + self: Component>, context: React.Context>, ): (props: P) => A } = Function.dual(2,

( @@ -403,7 +403,7 @@ export const withRuntime: { }) -export class ScopeMap extends Effect.Service()("effect-fc/Component/ScopeMap", { +export class ScopeMap extends Effect.Service()("@effect-fc/Component/ScopeMap", { effect: Effect.bind(Effect.Do, "ref", () => Ref.make(HashMap.empty())) }) {} diff --git a/packages/example/src/routeTree.gen.ts b/packages/example/src/routeTree.gen.ts index b842211..13eb94e 100644 --- a/packages/example/src/routeTree.gen.ts +++ b/packages/example/src/routeTree.gen.ts @@ -9,6 +9,7 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' +import { Route as ResultRouteImport } from './routes/result' import { Route as FormRouteImport } from './routes/form' import { Route as BlankRouteImport } from './routes/blank' import { Route as IndexRouteImport } from './routes/index' @@ -16,6 +17,11 @@ import { Route as DevMemoRouteImport } from './routes/dev/memo' import { Route as DevContextRouteImport } from './routes/dev/context' import { Route as DevAsyncRenderingRouteImport } from './routes/dev/async-rendering' +const ResultRoute = ResultRouteImport.update({ + id: '/result', + path: '/result', + getParentRoute: () => rootRouteImport, +} as any) const FormRoute = FormRouteImport.update({ id: '/form', path: '/form', @@ -51,6 +57,7 @@ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blank': typeof BlankRoute '/form': typeof FormRoute + '/result': typeof ResultRoute '/dev/async-rendering': typeof DevAsyncRenderingRoute '/dev/context': typeof DevContextRoute '/dev/memo': typeof DevMemoRoute @@ -59,6 +66,7 @@ export interface FileRoutesByTo { '/': typeof IndexRoute '/blank': typeof BlankRoute '/form': typeof FormRoute + '/result': typeof ResultRoute '/dev/async-rendering': typeof DevAsyncRenderingRoute '/dev/context': typeof DevContextRoute '/dev/memo': typeof DevMemoRoute @@ -68,6 +76,7 @@ export interface FileRoutesById { '/': typeof IndexRoute '/blank': typeof BlankRoute '/form': typeof FormRoute + '/result': typeof ResultRoute '/dev/async-rendering': typeof DevAsyncRenderingRoute '/dev/context': typeof DevContextRoute '/dev/memo': typeof DevMemoRoute @@ -78,6 +87,7 @@ export interface FileRouteTypes { | '/' | '/blank' | '/form' + | '/result' | '/dev/async-rendering' | '/dev/context' | '/dev/memo' @@ -86,6 +96,7 @@ export interface FileRouteTypes { | '/' | '/blank' | '/form' + | '/result' | '/dev/async-rendering' | '/dev/context' | '/dev/memo' @@ -94,6 +105,7 @@ export interface FileRouteTypes { | '/' | '/blank' | '/form' + | '/result' | '/dev/async-rendering' | '/dev/context' | '/dev/memo' @@ -103,6 +115,7 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute BlankRoute: typeof BlankRoute FormRoute: typeof FormRoute + ResultRoute: typeof ResultRoute DevAsyncRenderingRoute: typeof DevAsyncRenderingRoute DevContextRoute: typeof DevContextRoute DevMemoRoute: typeof DevMemoRoute @@ -110,6 +123,13 @@ export interface RootRouteChildren { declare module '@tanstack/react-router' { interface FileRoutesByPath { + '/result': { + id: '/result' + path: '/result' + fullPath: '/result' + preLoaderRoute: typeof ResultRouteImport + parentRoute: typeof rootRouteImport + } '/form': { id: '/form' path: '/form' @@ -159,6 +179,7 @@ const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BlankRoute: BlankRoute, FormRoute: FormRoute, + ResultRoute: ResultRoute, DevAsyncRenderingRoute: DevAsyncRenderingRoute, DevContextRoute: DevContextRoute, DevMemoRoute: DevMemoRoute, diff --git a/packages/example/src/routes/result.tsx b/packages/example/src/routes/result.tsx new file mode 100644 index 0000000..b87acb1 --- /dev/null +++ b/packages/example/src/routes/result.tsx @@ -0,0 +1,44 @@ +import { HttpClient } from "@effect/platform" +import { Container, Heading, Text } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Effect, Match, Schema } from "effect" +import { Component } from "effect-fc" +import { runtime } from "@/runtime" + + +const Post = Schema.Struct({ + userId: Schema.Int, + id: Schema.Int, + title: Schema.String, + body: Schema.String, +}) + +const Result = Component.makeUntraced("Result")(function*() { + const result = yield* Component.useOnMountResult(() => HttpClient.HttpClient.pipe( + Effect.andThen(client => client.get("https://jsonplaceholder.typicode.com/posts/1")), + Effect.andThen(Schema.decodeUnknown(Post)), + Effect.tap(Effect.sleep("250 millis")), + )) + + return ( + + {Match.value(result).pipe( + Match.tag("Running", () => Loading...), + Match.tag("Success", result => <> + {result.value.title} + {result.value.body} + ), + Match.tag("Failure", result => + An error has occured: {result.cause.toString()} + ), + Match.orElse(() => <>), + )} + + ) +}).pipe( + Component.withRuntime(runtime.context) +) + +export const Route = createFileRoute("/result")({ + component: Result +})