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

This commit is contained in:
Julien Valverdé
2025-07-23 03:29:04 +02:00
parent 5d045ecd1d
commit 7fdb2a799c
3 changed files with 33 additions and 7 deletions

View File

@@ -1,4 +1,4 @@
import { Context, Effect, ExecutionStrategy, Function, Pipeable, Predicate, Runtime, Scope, String, Tracer, type Utils } from "effect" import { Context, Effect, Effectable, ExecutionStrategy, Function, Predicate, Runtime, Scope, String, Tracer, type Utils } from "effect"
import * as React from "react" import * as React from "react"
import * as Hook from "./Hook.js" import * as Hook from "./Hook.js"
import * as Memoized from "./Memoized.js" import * as Memoized from "./Memoized.js"
@@ -7,7 +7,7 @@ import * as Memoized from "./Memoized.js"
export const TypeId: unique symbol = Symbol.for("effect-fc/Component") export const TypeId: unique symbol = Symbol.for("effect-fc/Component")
export type TypeId = typeof TypeId export type TypeId = typeof TypeId
export interface Component<E, R, P extends {}> extends Pipeable.Pipeable, Component.Options { export interface Component<E, R, P extends {}> extends Effect.Effect<React.FC<P>, never, R>, Component.Options {
new(_: never): {} new(_: never): {}
readonly [TypeId]: TypeId readonly [TypeId]: TypeId
/** @internal */ /** @internal */
@@ -30,8 +30,34 @@ export namespace Component {
const ComponentProto = Object.freeze({ const ComponentProto = Object.freeze({
...Effectable.CommitPrototype,
[TypeId]: TypeId, [TypeId]: TypeId,
pipe() { return Pipeable.pipeArguments(this, arguments) },
commit: Effect.fnUntraced(function* <E, R, P extends {}>(this: Component<E, R, P>) {
const self = this
const runtimeRef = React.useRef<Runtime.Runtime<Exclude<R, Scope.Scope>>>(null!)
runtimeRef.current = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
return React.useCallback(function ScopeProvider(props: P) {
const scope = Runtime.runSync(runtimeRef.current)(Hook.useScope(
Array.from(
Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
),
self,
))
const FC = React.useMemo(() => {
const f = self.makeFunctionComponent(runtimeRef, scope)
f.displayName = self.displayName ?? "Anonymous"
return Memoized.isMemoized(self)
? React.memo(f, self.propsAreEqual)
: f
}, [scope])
return React.createElement(FC, props)
}, [])
}),
makeFunctionComponent( makeFunctionComponent(
this: Component<any, any, any>, this: Component<any, any, any>,
@@ -52,7 +78,7 @@ const defaultOptions = {
const nonReactiveTags = [Tracer.ParentSpan] as const const nonReactiveTags = [Tracer.ParentSpan] as const
export const isComponent = (u: unknown): u is Component<any, any, any> => Predicate.hasProperty(u, TypeId) export const isComponent = (u: unknown): u is Component<unknown, unknown, {}> => Predicate.hasProperty(u, TypeId)
export namespace make { export namespace make {
export type Gen = { export type Gen = {

View File

@@ -21,7 +21,7 @@ const MemoizedProto = Object.freeze({
} as const) } as const)
export const isMemoized = (u: unknown): u is Memoized<any> => Predicate.hasProperty(u, TypeId) export const isMemoized = (u: unknown): u is Memoized<unknown> => Predicate.hasProperty(u, TypeId)
export const memo = <T extends Component.Component<any, any, any>>( export const memo = <T extends Component.Component<any, any, any>>(
self: T self: T

View File

@@ -9,8 +9,8 @@ import * as React from "react"
// Generator version // Generator version
const RouteComponent = Component.make(function* AsyncRendering() { const RouteComponent = Component.make(function* AsyncRendering() {
const VMemoizedAsyncComponent = yield* Component.useFC(MemoizedAsyncComponent) const VMemoizedAsyncComponent = yield* MemoizedAsyncComponent
const VAsyncComponent = yield* Component.useFC(AsyncComponent) const VAsyncComponent = yield* AsyncComponent
const [input, setInput] = React.useState("") const [input, setInput] = React.useState("")
return ( return (