Runtime refactoring
All checks were successful
Lint / lint (push) Successful in 11s

This commit is contained in:
Julien Valverdé
2025-08-21 01:57:53 +02:00
parent 37e4a5720f
commit 925a3d1264
5 changed files with 70 additions and 53 deletions

View File

@@ -1,47 +0,0 @@
import { Effect, type Layer, ManagedRuntime, type Runtime } from "effect"
import * as React from "react"
export interface ReactManagedRuntime<R, ER> {
readonly runtime: ManagedRuntime.ManagedRuntime<R, ER>
readonly context: React.Context<Runtime.Runtime<R>>
}
export const make = <R, ER>(
layer: Layer.Layer<R, ER>,
memoMap?: Layer.MemoMap,
): ReactManagedRuntime<R, ER> => ({
runtime: ManagedRuntime.make(layer, memoMap),
context: React.createContext<Runtime.Runtime<R>>(null!),
})
export interface ProviderProps<R, ER> extends React.SuspenseProps {
readonly runtime: ReactManagedRuntime<R, ER>
readonly children?: React.ReactNode
}
export function Provider<R, ER>(
{ runtime, children, ...suspenseProps }: ProviderProps<R, ER>
): React.ReactNode {
const promise = React.useMemo(() => Effect.runPromise(runtime.runtime.runtimeEffect), [runtime])
return React.createElement(
React.Suspense,
suspenseProps,
React.createElement(ProviderInner<R, ER>, { runtime, promise, children }),
)
}
interface ProviderInnerProps<R, ER> {
readonly runtime: ReactManagedRuntime<R, ER>
readonly promise: Promise<Runtime.Runtime<R>>
readonly children?: React.ReactNode
}
function ProviderInner<R, ER>(
{ runtime, promise, children }: ProviderInnerProps<R, ER>
): React.ReactNode {
const value = React.use(promise)
return React.createElement(runtime.context, { value }, children)
}

View File

@@ -0,0 +1,64 @@
import { Effect, type Layer, ManagedRuntime, Predicate, type Runtime } from "effect"
import * as React from "react"
export const TypeId: unique symbol = Symbol.for("effect-fc/ReactRuntime")
export type TypeId = typeof TypeId
export interface ReactRuntime<R, ER> {
new(_: never): {}
readonly [TypeId]: TypeId
readonly runtime: ManagedRuntime.ManagedRuntime<R, ER>
readonly context: React.Context<Runtime.Runtime<R>>
}
const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const)
export const isReactRuntime = (u: unknown): u is ReactRuntime<unknown, unknown> => Predicate.hasProperty(u, TypeId)
export const make = <R, ER>(
layer: Layer.Layer<R, ER>,
memoMap?: Layer.MemoMap,
): ReactRuntime<R, ER> => Object.setPrototypeOf(
Object.assign(function() {}, {
runtime: ManagedRuntime.make(layer, memoMap),
context: React.createContext<Runtime.Runtime<R>>(null!),
}),
ReactRuntimeProto,
)
export namespace Provider {
export interface Props<R, ER> extends React.SuspenseProps {
readonly runtime: ReactRuntime<R, ER>
readonly children?: React.ReactNode
}
}
export const Provider = <R, ER>(
{ runtime, children, ...suspenseProps }: Provider.Props<R, ER>
): React.ReactNode => {
const promise = React.useMemo(() => Effect.runPromise(runtime.runtime.runtimeEffect), [runtime])
return React.createElement(
React.Suspense,
suspenseProps,
React.createElement(ProviderInner<R, ER>, { runtime, promise, children }),
)
}
namespace ProviderInner {
export interface Props<R, ER> {
readonly runtime: ReactRuntime<R, ER>
readonly promise: Promise<Runtime.Runtime<R>>
readonly children?: React.ReactNode
}
}
const ProviderInner = <R, ER>(
{ runtime, promise, children }: ProviderInner.Props<R, ER>
): React.ReactNode => {
const value = React.use(promise)
return React.createElement(runtime.context, { value }, children)
}

View File

@@ -1,4 +1,4 @@
export * as Component from "./Component.js" export * as Component from "./Component.js"
export * as Memo from "./Memo.js" export * as Memo from "./Memo.js"
export * as ReactManagedRuntime from "./ReactManagedRuntime.js" export * as ReactRuntime from "./ReactRuntime.js"
export * as Suspense from "./Suspense.js" export * as Suspense from "./Suspense.js"

View File

@@ -1,5 +1,5 @@
import { createRouter, RouterProvider } from "@tanstack/react-router" import { createRouter, RouterProvider } from "@tanstack/react-router"
import { ReactManagedRuntime } from "effect-fc" import { ReactRuntime } from "effect-fc"
import { StrictMode } from "react" import { StrictMode } from "react"
import { createRoot } from "react-dom/client" import { createRoot } from "react-dom/client"
import { routeTree } from "./routeTree.gen" import { routeTree } from "./routeTree.gen"
@@ -16,8 +16,8 @@ declare module "@tanstack/react-router" {
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>
<ReactManagedRuntime.Provider runtime={runtime}> <ReactRuntime.Provider runtime={runtime}>
<RouterProvider router={router} /> <RouterProvider router={router} />
</ReactManagedRuntime.Provider> </ReactRuntime.Provider>
</StrictMode> </StrictMode>
) )

View File

@@ -1,7 +1,7 @@
import { FetchHttpClient } from "@effect/platform" import { FetchHttpClient } from "@effect/platform"
import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser" import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser"
import { DateTime, Layer } from "effect" import { DateTime, Layer } from "effect"
import { ReactManagedRuntime } from "effect-fc" import { ReactRuntime } from "effect-fc"
export const AppLive = Layer.empty.pipe( export const AppLive = Layer.empty.pipe(
@@ -12,4 +12,4 @@ export const AppLive = Layer.empty.pipe(
Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(FetchHttpClient.layer),
) )
export const runtime = ReactManagedRuntime.make(AppLive) export const runtime = ReactRuntime.make(AppLive)