@@ -89,11 +89,11 @@ Use `Component.make` when you want automatic tracing spans, or
|
||||
`Component.makeUntraced` when you only want the component behavior. This creates
|
||||
an Effect-FC component, not a plain React component yet.
|
||||
|
||||
```tsx title="src/HelloEffect.tsx"
|
||||
```tsx title="src/HelloView.tsx"
|
||||
import { Effect } from "effect"
|
||||
import { Component } from "effect-fc"
|
||||
|
||||
export const HelloEffect = Component.make("HelloEffect")(function* (props: {
|
||||
export const HelloView = Component.make("HelloView")(function* (props: {
|
||||
readonly name: string
|
||||
}) {
|
||||
const message = yield* Effect.succeed(`Hello, ${props.name}`)
|
||||
@@ -102,7 +102,7 @@ export const HelloEffect = Component.make("HelloEffect")(function* (props: {
|
||||
})
|
||||
```
|
||||
|
||||
At this point `HelloEffect` can yield Effects, services, and scoped lifecycle
|
||||
At this point `HelloView` can yield Effects, services, and scoped lifecycle
|
||||
work, but React cannot render it directly.
|
||||
|
||||
## Apply A Runtime
|
||||
@@ -112,10 +112,10 @@ to become a regular React function component.
|
||||
|
||||
```tsx title="src/Hello.tsx"
|
||||
import { Component } from "effect-fc"
|
||||
import { HelloEffect } from "./HelloEffect"
|
||||
import { HelloView } from "./HelloView"
|
||||
import { runtime } from "./runtime"
|
||||
|
||||
export const Hello = HelloEffect.pipe(
|
||||
export const Hello = HelloView.pipe(
|
||||
Component.withRuntime(runtime.context),
|
||||
)
|
||||
```
|
||||
@@ -136,13 +136,13 @@ Inside an Effect-FC component, other Effect-FC components are available through
|
||||
their `.use` effect. Yield `.use` to get a React component for the current
|
||||
runtime context, then render it like JSX.
|
||||
|
||||
```tsx title="src/GreetingCardEffect.tsx"
|
||||
```tsx title="src/GreetingCardView.tsx"
|
||||
import { Component } from "effect-fc"
|
||||
import { HelloEffect } from "./HelloEffect"
|
||||
import { HelloView } from "./HelloView"
|
||||
|
||||
export const GreetingCardEffect = Component.make("GreetingCard")(
|
||||
export const GreetingCardView = Component.make("GreetingCard")(
|
||||
function* () {
|
||||
const Hello = yield* HelloEffect.use
|
||||
const Hello = yield* HelloView.use
|
||||
|
||||
return (
|
||||
<section>
|
||||
@@ -159,10 +159,10 @@ normal React component again:
|
||||
|
||||
```tsx title="src/GreetingCard.tsx"
|
||||
import { Component } from "effect-fc"
|
||||
import { GreetingCardEffect } from "./GreetingCardEffect"
|
||||
import { GreetingCardView } from "./GreetingCardView"
|
||||
import { runtime } from "./runtime"
|
||||
|
||||
export const GreetingCard = GreetingCardEffect.pipe(
|
||||
export const GreetingCard = GreetingCardView.pipe(
|
||||
Component.withRuntime(runtime.context),
|
||||
)
|
||||
```
|
||||
@@ -177,11 +177,11 @@ The component scope is created when React mounts the component and closes when
|
||||
React unmounts it. When the scope closes, Effect runs the finalizers registered
|
||||
inside that scope.
|
||||
|
||||
```tsx title="src/MountedMessageEffect.tsx"
|
||||
```tsx title="src/MountedMessageView.tsx"
|
||||
import { Console, Effect } from "effect"
|
||||
import { Component } from "effect-fc"
|
||||
|
||||
export const MountedMessageEffect = Component.make("MountedMessage")(
|
||||
export const MountedMessageView = Component.make("MountedMessage")(
|
||||
function* () {
|
||||
const message = yield* Component.useOnMount(() =>
|
||||
Effect.gen(function* () {
|
||||
@@ -207,7 +207,7 @@ work should be recreated when dependencies change.
|
||||
import { Console, Effect } from "effect"
|
||||
import { Component } from "effect-fc"
|
||||
|
||||
const UserPanelEffect = Component.make("UserPanel")(
|
||||
const UserPanelView = Component.make("UserPanel")(
|
||||
function* (props: { readonly userId: string }) {
|
||||
const user = yield* Component.useOnChange(
|
||||
() =>
|
||||
@@ -307,7 +307,7 @@ including React hooks, refs, event handlers, context, and JSX composition.
|
||||
import { Component } from "effect-fc"
|
||||
import * as React from "react"
|
||||
|
||||
const CounterEffect = Component.make("Counter")(function* () {
|
||||
const CounterView = Component.make("Counter")(function* () {
|
||||
const [count, setCount] = React.useState(0)
|
||||
const buttonRef = React.useRef<HTMLButtonElement>(null)
|
||||
|
||||
@@ -362,7 +362,7 @@ import { Component } from "effect-fc"
|
||||
import { runtime } from "./runtime"
|
||||
import { GreetingService } from "./services"
|
||||
|
||||
const GreetingEffect = Component.make("Greeting")(function* (props: {
|
||||
const GreetingView = Component.make("Greeting")(function* (props: {
|
||||
readonly name: string
|
||||
}) {
|
||||
const greeting = yield* GreetingService
|
||||
@@ -370,35 +370,11 @@ const GreetingEffect = Component.make("Greeting")(function* (props: {
|
||||
return <p>{greeting.greet(props.name)}</p>
|
||||
})
|
||||
|
||||
export const Greeting = GreetingEffect.pipe(
|
||||
export const Greeting = GreetingView.pipe(
|
||||
Component.withRuntime(runtime.context),
|
||||
)
|
||||
```
|
||||
|
||||
## Mount And Cleanup Effects
|
||||
|
||||
Use `Component.useOnMount` for scoped work that should start when the component
|
||||
mounts and finalize when it unmounts.
|
||||
|
||||
```tsx
|
||||
import { Console, Effect } from "effect"
|
||||
import { Component } from "effect-fc"
|
||||
|
||||
const Mounted = Component.make("Mounted")(function* () {
|
||||
yield* Component.useOnMount(() =>
|
||||
Effect.gen(function* () {
|
||||
yield* Console.log("Mounted")
|
||||
yield* Effect.addFinalizer(() => Console.log("Unmounted"))
|
||||
}),
|
||||
)
|
||||
|
||||
return <p>Open the console, then unmount me.</p>
|
||||
})
|
||||
```
|
||||
|
||||
Finalizers are tied to the component scope, so this is the right place for
|
||||
subscriptions, resources, and other lifecycle-bound Effects.
|
||||
|
||||
## Where To Go Next
|
||||
|
||||
Once the runtime and component boundary are in place, the rest of the library
|
||||
|
||||
Reference in New Issue
Block a user