5 Commits

Author SHA1 Message Date
7b2d9ae2a4 Update dependency @effect/language-service to ^0.76.0
All checks were successful
Lint / lint (push) Successful in 42s
Test build / test-build (pull_request) Successful in 57s
2026-02-25 12:01:46 +00:00
Julien Valverdé
a73da25b8c Fix
All checks were successful
Lint / lint (push) Successful in 12s
2026-02-25 03:18:24 +01:00
Julien Valverdé
d0bc4e4903 Refactor Component
All checks were successful
Lint / lint (push) Successful in 43s
2026-02-25 03:09:51 +01:00
0ae55bd02c Update dependency @effect/language-service to ^0.75.0 (#34)
All checks were successful
Lint / lint (push) Successful in 14s
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@effect/language-service](https://github.com/Effect-TS/language-service) | [`^0.72.0` → `^0.75.0`](https://renovatebot.com/diffs/npm/@effect%2flanguage-service/0.72.1/0.75.1) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@effect%2flanguage-service/0.75.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@effect%2flanguage-service/0.72.1/0.75.1?slim=true) |

---

### Release Notes

<details>
<summary>Effect-TS/language-service (@&#8203;effect/language-service)</summary>

### [`v0.75.1`](https://github.com/Effect-TS/language-service/releases/tag/%40effect/language-service%400.75.1)

[Compare Source](https://github.com/Effect-TS/language-service/compare/@effect/language-service@0.75.0...@effect/language-service@0.75.1)

##### Patch Changes

- [#&#8203;647](https://github.com/Effect-TS/language-service/pull/647) [`489e3f0`](489e3f0572) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Expose diagnostic quick fixes as refactoring actions to work around TypeScript's limited quick fix handling in some contexts

- [#&#8203;650](https://github.com/Effect-TS/language-service/pull/650) [`6f568cf`](6f568cf37a) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Fix TypeParser to skip types with generic call signatures. When parsing covariant, contravariant, or invariant types, signatures with type parameters are now correctly rejected instead of being treated as concrete types.

- [#&#8203;649](https://github.com/Effect-TS/language-service/pull/649) [`5858fd1`](5858fd1d87) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Performance improvements: replace `Nano.gen` with `Nano.fn` named functions across diagnostics, refactors, and code generation modules for better performance tracking and reduced runtime overhead. Add conditional `debugPerformance` flag to avoid unnecessary timing collection when not debugging.

### [`v0.75.0`](https://github.com/Effect-TS/language-service/releases/tag/%40effect/language-service%400.75.0)

[Compare Source](https://github.com/Effect-TS/language-service/compare/@effect/language-service@0.74.0...@effect/language-service@0.75.0)

##### Minor Changes

- [#&#8203;645](https://github.com/Effect-TS/language-service/pull/645) [`a8a7d33`](a8a7d33f3a) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add `ServiceMap.Service` class completion for Effect v4, and fix Schema class completions for v4 (`TaggedErrorClass`, `TaggedClass` now available, `ErrorClass` fully-qualified form fixed, `RequestClass` removed)

### [`v0.74.0`](https://github.com/Effect-TS/language-service/releases/tag/%40effect/language-service%400.74.0)

[Compare Source](https://github.com/Effect-TS/language-service/compare/@effect/language-service@0.73.1...@effect/language-service@0.74.0)

##### Minor Changes

- [#&#8203;641](https://github.com/Effect-TS/language-service/pull/641) [`693e5a5`](693e5a5ef2) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Added Effect v4 support for diagnostics, refactors, and piping features.

  **Diagnostics:**

  - `multipleEffectProvide`: Warns when multiple `Effect.provide` calls are chained, suggesting consolidation
  - `strictEffectProvide`: Warns when using `Effect.provide` with Layer outside of application entry points
  - `missingLayerContext`: Detects missing Layer context requirements
  - `deterministicKeys`: Extended to support `ServiceMap.Service` patterns
  - `leakingRequirements`: Extended to detect leaking requirements in ServiceMap services
  - `schemaSyncInEffect`: Updated with v4-specific method mappings (e.g., `decodeSync` -> `decodeEffect`)

  **Refactors:**

  - `layerMagic`: Automatically compose and build layers based on service dependencies
  - `structuralTypeToSchema`: Convert TypeScript interfaces and type aliases to Effect Schema classes
  - `makeSchemaOpaque`: Enhanced for v4 with support for `Codec`, `DecodingServices`, and `EncodingServices` types
  - `typeToEffectSchema`: Enhanced to support Effect v4 schema patterns

  **Piping:**

  - Added pipe transformation support for Effect v4 including `Effect.fn`, nested pipes, and function call conversions

##### Patch Changes

- [#&#8203;643](https://github.com/Effect-TS/language-service/pull/643) [`68f6d12`](68f6d120ad) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Disable `schemaUnionOfLiterals` diagnostic for Effect v4, as `Schema.Union` of multiple `Schema.Literal` calls is no longer applicable in v4.

### [`v0.73.1`](https://github.com/Effect-TS/language-service/releases/tag/%40effect/language-service%400.73.1)

[Compare Source](https://github.com/Effect-TS/language-service/compare/@effect/language-service@0.73.0...@effect/language-service@0.73.1)

##### Patch Changes

- [#&#8203;639](https://github.com/Effect-TS/language-service/pull/639) [`ff72045`](ff72045531) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add wildcard (`*`) support for `@effect-diagnostics` comment directives. You can now use `*` as a rule name to apply a severity override to all diagnostics at once, e.g. `@effect-diagnostics *:off` disables all Effect diagnostics from that point on. Rule-specific overrides still take precedence over wildcard overrides.

### [`v0.73.0`](https://github.com/Effect-TS/language-service/releases/tag/%40effect/language-service%400.73.0)

[Compare Source](https://github.com/Effect-TS/language-service/compare/@effect/language-service@0.72.1...@effect/language-service@0.73.0)

##### Minor Changes

- [#&#8203;637](https://github.com/Effect-TS/language-service/pull/637) [`616c2cc`](616c2cc21c) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add Effect v4 completions support

  - Detect installed Effect version (v3 or v4) and conditionally enable version-specific completions
  - Add `Schema.ErrorClass` and `Schema.RequestClass` completions for Effect v4
  - Disable v3-only completions (`Effect.Service`, `Effect.Tag`, `Schema.TaggedError`, `Schema.TaggedClass`, `Schema.TaggedRequest`, `Context.Tag` self, `Rpc.make` classes, `Schema.brand`, `Model.Class`) when Effect v4 is detected
  - Support lowercase `taggedEnum` in addition to `TaggedEnum` for v4 API compatibility

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4zLjQiLCJ1cGRhdGVkSW5WZXIiOiI0My4yNy4wIiwidGFyZ2V0QnJhbmNoIjoibmV4dCIsImxhYmVscyI6W119-->

Reviewed-on: #34
Co-authored-by: Renovate Bot <renovate-bot@valverde.cloud>
Co-committed-by: Renovate Bot <renovate-bot@valverde.cloud>
2026-02-23 23:32:07 +01:00
Julien Valverdé
bb044e766d Fix README
All checks were successful
Lint / lint (push) Successful in 58s
2026-01-23 01:55:10 +01:00
13 changed files with 123 additions and 107 deletions

View File

@@ -1,6 +1,6 @@
# Effect FC Monorepo
[Effect-TS](https://effect.website/) integration for React 19+ that allows you to write function components using Effect generators.
[Effect-TS](https://effect.website/) integration for React 19.2+ that allows you to write function components using Effect generators.
This monorepo contains:
- [The `effect-fc` library](packages/effect-fc)

View File

@@ -6,7 +6,7 @@
"name": "@effect-fc/monorepo",
"devDependencies": {
"@biomejs/biome": "^2.3.11",
"@effect/language-service": "^0.72.0",
"@effect/language-service": "^0.76.0",
"@types/bun": "^1.3.6",
"npm-check-updates": "^19.3.1",
"npm-sort": "^0.0.4",
@@ -16,7 +16,7 @@
},
"packages/effect-fc": {
"name": "effect-fc",
"version": "0.2.2",
"version": "0.2.3",
"devDependencies": {
"@effect/platform-browser": "^0.74.0",
},
@@ -116,7 +116,7 @@
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
"@effect/language-service": ["@effect/language-service@0.72.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-MWkyTPCXSs5Q3OIBWR3q24SA+ipkdWW7EBJBt6EPUzlzZxjJLXtLBhXpMoCFheSEM0FTWOHT4BRLh5lufsmjVw=="],
"@effect/language-service": ["@effect/language-service@0.76.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-tCFQjdvdeqSx+j+QCA9dbz5K4BJtsvIknH8sHft8pTT8ClmVr7uAghD7TcufCtDOZQunXRXyKqQZzErduqhSYQ=="],
"@effect/platform": ["@effect/platform@0.94.2", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.15" } }, "sha512-85vdwpnK4oH/rJ3EuX/Gi2Hkt+K4HvXWr9bxCuqvty9hxyEcRxkJcqTesYrcVoQB6aULb1Za2B0MKoTbvffB3Q=="],

View File

@@ -16,7 +16,7 @@
},
"devDependencies": {
"@biomejs/biome": "^2.3.11",
"@effect/language-service": "^0.72.0",
"@effect/language-service": "^0.76.0",
"@types/bun": "^1.3.6",
"npm-check-updates": "^19.3.1",
"npm-sort": "^0.0.4",

View File

@@ -7,29 +7,27 @@ import * as Component from "./Component.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/Async/Async")
export type TypeId = typeof TypeId
export interface Async extends Async.Options {
export interface Async extends AsyncOptions {
readonly [TypeId]: TypeId
}
export namespace Async {
export interface Options {
export interface AsyncOptions {
readonly defaultFallback?: React.ReactNode
}
export type Props = Omit<React.SuspenseProps, "children">
}
export type AsyncProps = Omit<React.SuspenseProps, "children">
const AsyncProto = Object.freeze({
export const AsyncPrototype = Object.freeze({
[TypeId]: TypeId,
makeFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
asFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
this: Component.Component<P, A, E, R> & Async,
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
) {
const SuspenseInner = (props: { readonly promise: Promise<React.ReactNode> }) => React.use(props.promise)
return ({ fallback, name, ...props }: Async.Props) => {
return ({ fallback, name, ...props }: AsyncProps) => {
const promise = Runtime.runPromise(runtimeRef.current)(
Effect.andThen(
Component.useScope([], this),
@@ -54,7 +52,7 @@ export const async = <T extends Component.Component<any, any, any, any>>(
): (
& Omit<T, keyof Component.Component.AsComponent<T>>
& Component.Component<
Component.Component.Props<T> & Async.Props,
Component.Component.Props<T> & AsyncProps,
Component.Component.Success<T>,
Component.Component.Error<T>,
Component.Component.Context<T>
@@ -63,22 +61,22 @@ export const async = <T extends Component.Component<any, any, any, any>>(
) => Object.setPrototypeOf(
Object.assign(function() {}, self),
Object.freeze(Object.setPrototypeOf(
Object.assign({}, AsyncProto),
Object.assign({}, AsyncPrototype),
Object.getPrototypeOf(self),
)),
)
export const withOptions: {
<T extends Component.Component<any, any, any, any> & Async>(
options: Partial<Async.Options>
options: Partial<AsyncOptions>
): (self: T) => T
<T extends Component.Component<any, any, any, any> & Async>(
self: T,
options: Partial<Async.Options>,
options: Partial<AsyncOptions>,
): T
} = Function.dual(2, <T extends Component.Component<any, any, any, any> & Async>(
self: T,
options: Partial<Async.Options>,
options: Partial<AsyncOptions>,
): T => Object.setPrototypeOf(
Object.assign(function() {}, self, options),
Object.getPrototypeOf(self),

View File

@@ -1,8 +1,7 @@
/** 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, Tracer, type Utils } from "effect"
import { Context, type Duration, Effect, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, identity, Layer, ManagedRuntime, Option, Pipeable, Predicate, Ref, Runtime, Scope, Tracer, type Utils } from "effect"
import * as React from "react"
import { Memoized } from "./index.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/Component/Component")
@@ -16,10 +15,7 @@ export type TypeId = typeof TypeId
* - a constructor-like object with component metadata and options
*/
export interface Component<P extends {}, A extends React.ReactNode, E, R>
extends
Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>,
Component.Options
{
extends ComponentPrototype<P, A, R>, ComponentOptions {
new(_: never): Record<string, never>
readonly [TypeId]: TypeId
readonly "~Props": P
@@ -28,11 +24,6 @@ extends
readonly "~Context": R
readonly body: (props: P) => Effect.Effect<A, E, R>
/** @internal */
makeFunctionComponent(
runtimeRef: React.Ref<Runtime.Runtime<Exclude<R, Scope.Scope>>>
): (props: P) => A
}
export declare namespace Component {
@@ -42,11 +33,71 @@ export declare namespace Component {
export type Context<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer _A, infer _E, infer R>] ? R : never
export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>>
}
/**
* Options that can be set on the component
*/
export interface Options {
export interface ComponentPrototype<P extends {}, A extends React.ReactNode, R>
extends Pipeable.Pipeable {
readonly [TypeId]: TypeId
readonly use: Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>
asFunctionComponent(
runtimeRef: React.Ref<Runtime.Runtime<Exclude<R, Scope.Scope>>>
): (props: P) => A
setFunctionComponentName(f: React.FC<P>): void
transformFunctionComponent(f: React.FC<P>): React.FC<P>
}
export const ComponentPrototype: ComponentPrototype<any, any, any> = Object.freeze({
[TypeId]: TypeId,
...Pipeable.Prototype,
get use() { return use(this) },
asFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
this: Component<P, A, E, R>,
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
) {
return (props: P) => Runtime.runSync(runtimeRef.current)(
Effect.andThen(
useScope([], this),
scope => Effect.provideService(this.body(props), Scope.Scope, scope),
)
)
},
setFunctionComponentName<P extends {}, A extends React.ReactNode, E, R>(
this: Component<P, A, E, R>,
f: React.FC<P>,
) {
f.displayName = this.displayName ?? "Anonymous"
},
transformFunctionComponent: identity,
} as const)
const use = Effect.fnUntraced(function* <P extends {}, A extends React.ReactNode, E, R>(
self: Component<P, A, E, R>
) {
// biome-ignore lint/style/noNonNullAssertion: React ref initialization
const runtimeRef = React.useRef<Runtime.Runtime<Exclude<R, Scope.Scope>>>(null!)
runtimeRef.current = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
return yield* React.useState(() => Runtime.runSync(runtimeRef.current)(Effect.cachedFunction(
(_services: readonly any[]) => Effect.sync(() => {
const f: React.FC<P> = self.asFunctionComponent(runtimeRef)
self.setFunctionComponentName(f)
return self.transformFunctionComponent(f)
}),
Equivalence.array(Equivalence.strict()),
)))[0](Array.from(
Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
))
})
export interface ComponentOptions {
/** Custom displayName for React DevTools and debugging. */
readonly displayName?: string
@@ -62,54 +113,15 @@ export declare namespace Component {
* @default "100 millis"
*/
readonly finalizerExecutionDebounce: Duration.DurationInput
}
}
const ComponentProto = Object.freeze({
...Effectable.CommitPrototype,
[TypeId]: TypeId,
commit: Effect.fnUntraced(function* <P extends {}, A extends React.ReactNode, E, R>(
this: Component<P, A, E, R>
) {
// biome-ignore lint/style/noNonNullAssertion: React ref initialization
const runtimeRef = React.useRef<Runtime.Runtime<Exclude<R, Scope.Scope>>>(null!)
runtimeRef.current = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
return yield* React.useState(() => Runtime.runSync(runtimeRef.current)(Effect.cachedFunction(
(_services: readonly any[]) => Effect.sync(() => {
const f: React.FC<P> = this.makeFunctionComponent(runtimeRef)
f.displayName = this.displayName ?? "Anonymous"
return Memoized.isMemoized(this)
? React.memo(f, this.propsAreEqual)
: f
}),
Equivalence.array(Equivalence.strict()),
)))[0](Array.from(
Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
))
}),
makeFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
this: Component<P, A, E, R>,
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
) {
return (props: P) => Runtime.runSync(runtimeRef.current)(
Effect.andThen(
useScope([], this),
scope => Effect.provideService(this.body(props), Scope.Scope, scope),
)
)
},
} as const)
const defaultOptions: Component.Options = {
export const defaultOptions: ComponentOptions = {
finalizerExecutionStrategy: ExecutionStrategy.sequential,
finalizerExecutionDebounce: "100 millis",
}
const nonReactiveTags = [Tracer.ParentSpan] as const
export const nonReactiveTags = [Tracer.ParentSpan] as const
export const isComponent = (u: unknown): u is Component<{}, React.ReactNode, unknown, unknown> => Predicate.hasProperty(u, TypeId)
@@ -365,7 +377,7 @@ export const make: (
Object.assign(function() {}, defaultOptions, {
body: Effect.fn(spanNameOrBody as any, ...pipeables),
}),
ComponentProto,
ComponentPrototype,
)
}
else {
@@ -375,7 +387,7 @@ export const make: (
body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []),
displayName: spanNameOrBody,
}),
ComponentProto,
ComponentPrototype,
)
}
}
@@ -401,14 +413,14 @@ export const makeUntraced: (
Object.assign(function() {}, defaultOptions, {
body: Effect.fnUntraced(spanNameOrBody as any, ...pipeables as []),
}),
ComponentProto,
ComponentPrototype,
)
: (body: any, ...pipeables: any[]) => Object.setPrototypeOf(
Object.assign(function() {}, defaultOptions, {
body: Effect.fnUntraced(body, ...pipeables as []),
displayName: spanNameOrBody,
}),
ComponentProto,
ComponentPrototype,
)
)
@@ -417,15 +429,15 @@ export const makeUntraced: (
*/
export const withOptions: {
<T extends Component<any, any, any, any>>(
options: Partial<Component.Options>
options: Partial<ComponentOptions>
): (self: T) => T
<T extends Component<any, any, any, any>>(
self: T,
options: Partial<Component.Options>,
options: Partial<ComponentOptions>,
): T
} = Function.dual(2, <T extends Component<any, any, any, any>>(
self: T,
options: Partial<Component.Options>,
options: Partial<ComponentOptions>,
): T => Object.setPrototypeOf(
Object.assign(function() {}, self, options),
Object.getPrototypeOf(self),
@@ -477,7 +489,7 @@ export const withRuntime: {
context: React.Context<Runtime.Runtime<R>>,
) => function WithRuntime(props: P) {
return React.createElement(
Runtime.runSync(React.useContext(context))(self),
Runtime.runSync(React.useContext(context))(self.use),
props,
)
})

View File

@@ -1,24 +1,30 @@
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
import { type Equivalence, Function, Predicate } from "effect"
import * as React from "react"
import type * as Component from "./Component.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/Memoized/Memoized")
export type TypeId = typeof TypeId
export interface Memoized<P> extends Memoized.Options<P> {
export interface Memoized<P> extends MemoizedOptions<P> {
readonly [TypeId]: TypeId
}
export namespace Memoized {
export interface Options<P> {
readonly propsAreEqual?: Equivalence.Equivalence<P>
}
export interface MemoizedOptions<P> {
readonly propsEquivalence?: Equivalence.Equivalence<P>
}
const MemoizedProto = Object.freeze({
[TypeId]: TypeId
export const MemoizedPrototype = Object.freeze({
[TypeId]: TypeId,
transformFunctionComponent<P extends {}>(
this: Memoized<P>,
f: React.FC<P>,
) {
return React.memo(f, this.propsEquivalence)
},
} as const)
@@ -29,22 +35,22 @@ export const memoized = <T extends Component.Component<any, any, any, any>>(
): T & Memoized<Component.Component.Props<T>> => Object.setPrototypeOf(
Object.assign(function() {}, self),
Object.freeze(Object.setPrototypeOf(
Object.assign({}, MemoizedProto),
Object.assign({}, MemoizedPrototype),
Object.getPrototypeOf(self),
)),
)
export const withOptions: {
<T extends Component.Component<any, any, any, any> & Memoized<any>>(
options: Partial<Memoized.Options<Component.Component.Props<T>>>
options: Partial<MemoizedOptions<Component.Component.Props<T>>>
): (self: T) => T
<T extends Component.Component<any, any, any, any> & Memoized<any>>(
self: T,
options: Partial<Memoized.Options<Component.Component.Props<T>>>,
options: Partial<MemoizedOptions<Component.Component.Props<T>>>,
): T
} = Function.dual(2, <T extends Component.Component<any, any, any, any> & Memoized<any>>(
self: T,
options: Partial<Memoized.Options<Component.Component.Props<T>>>,
options: Partial<MemoizedOptions<Component.Component.Props<T>>>,
): T => Object.setPrototypeOf(
Object.assign(function() {}, self, options),
Object.getPrototypeOf(self),

View File

@@ -9,8 +9,8 @@ import { runtime } from "@/runtime"
// Generator version
const RouteComponent = Component.makeUntraced(function* AsyncRendering() {
const MemoizedAsyncComponentFC = yield* MemoizedAsyncComponent
const AsyncComponentFC = yield* AsyncComponent
const MemoizedAsyncComponentFC = yield* MemoizedAsyncComponent.use
const AsyncComponentFC = yield* AsyncComponent.use
const [input, setInput] = React.useState("")
return (
@@ -51,7 +51,7 @@ const RouteComponent = Component.makeUntraced(function* AsyncRendering() {
class AsyncComponent extends Component.makeUntraced("AsyncComponent")(function*() {
const SubComponentFC = yield* SubComponent
const SubComponentFC = yield* SubComponent.use
yield* Effect.sleep("500 millis") // Async operation
// Cannot use React hooks after the async operation

View File

@@ -23,7 +23,7 @@ const SubComponent = Component.makeUntraced("SubComponent")(function*() {
const ContextView = Component.makeUntraced("ContextView")(function*() {
const [serviceValue, setServiceValue] = React.useState("test")
const SubServiceLayer = React.useMemo(() => SubService.Default(serviceValue), [serviceValue])
const SubComponentFC = yield* Effect.provide(SubComponent, yield* Component.useContext(SubServiceLayer))
const SubComponentFC = yield* Effect.provide(SubComponent.use, yield* Component.useContext(SubServiceLayer))
return (
<Container>

View File

@@ -17,8 +17,8 @@ const RouteComponent = Component.makeUntraced("RouteComponent")(function*() {
onChange={e => setValue(e.target.value)}
/>
{yield* Effect.map(SubComponent, FC => <FC />)}
{yield* Effect.map(MemoizedSubComponent, FC => <FC />)}
{yield* Effect.map(SubComponent.use, FC => <FC />)}
{yield* Effect.map(MemoizedSubComponent.use, FC => <FC />)}
</Flex>
)
}).pipe(

View File

@@ -70,7 +70,7 @@ class RegisterFormView extends Component.makeUntraced("RegisterFormView")(functi
])
const runPromise = yield* Component.useRunPromise()
const TextFieldFormInputFC = yield* TextFieldFormInput
const TextFieldFormInputFC = yield* TextFieldFormInput.use
yield* Component.useOnMount(() => Effect.gen(function*() {
yield* Effect.addFinalizer(() => Console.log("RegisterFormView unmounted"))
@@ -117,7 +117,7 @@ class RegisterFormView extends Component.makeUntraced("RegisterFormView")(functi
const RegisterPage = Component.makeUntraced("RegisterPage")(function*() {
const RegisterFormViewFC = yield* Effect.provide(
RegisterFormView,
RegisterFormView.use,
yield* Component.useContext(RegisterForm.Default),
)

View File

@@ -10,7 +10,7 @@ const TodosStateLive = TodosState.Default("todos")
const Index = Component.makeUntraced("Index")(function*() {
const TodosFC = yield* Effect.provide(
Todos,
Todos.use,
yield* Component.useContext(TodosStateLive),
)

View File

@@ -83,7 +83,7 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr
const runSync = yield* Component.useRunSync()
const runPromise = yield* Component.useRunPromise<DateTime.CurrentTimeZone>()
const TextFieldFormInputFC = yield* TextFieldFormInput
const TextFieldFormInputFC = yield* TextFieldFormInput.use
return (

View File

@@ -14,7 +14,7 @@ export class Todos extends Component.makeUntraced("Todos")(function*() {
Effect.addFinalizer(() => Console.log("Todos unmounted")),
))
const TodoFC = yield* Todo
const TodoFC = yield* Todo.use
return (
<Container>