Co-authored-by: Julien Valverdé <julien.valverde@mailo.com> Reviewed-on: #5
79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
import { Flex, Text, TextField } from "@radix-ui/themes"
|
|
import { createFileRoute } from "@tanstack/react-router"
|
|
import { GetRandomValues, makeUuid4 } from "@typed/id"
|
|
import { Effect } from "effect"
|
|
import { Async, Component, Hooks, Memoized } from "effect-fc"
|
|
import * as React from "react"
|
|
import { runtime } from "@/runtime"
|
|
|
|
|
|
// Generator version
|
|
const RouteComponent = Component.makeUntraced(function* AsyncRendering() {
|
|
const MemoizedAsyncComponentFC = yield* MemoizedAsyncComponent
|
|
const AsyncComponentFC = yield* AsyncComponent
|
|
const [input, setInput] = React.useState("")
|
|
|
|
return (
|
|
<Flex direction="column" align="stretch" gap="2">
|
|
<TextField.Root
|
|
value={input}
|
|
onChange={e => setInput(e.target.value)}
|
|
/>
|
|
|
|
<MemoizedAsyncComponentFC fallback={React.useMemo(() => <p>Loading memoized...</p>, [])} />
|
|
<AsyncComponentFC />
|
|
</Flex>
|
|
)
|
|
}).pipe(
|
|
Component.withRuntime(runtime.context)
|
|
)
|
|
|
|
// Pipeline version
|
|
// const RouteComponent = Component.make("RouteComponent")(() => Effect.Do,
|
|
// Effect.bind("VMemoizedAsyncComponent", () => Component.useFC(MemoizedAsyncComponent)),
|
|
// Effect.bind("VAsyncComponent", () => Component.useFC(AsyncComponent)),
|
|
// Effect.let("input", () => React.useState("")),
|
|
|
|
// Effect.map(({ input: [input, setInput], VAsyncComponent, VMemoizedAsyncComponent }) =>
|
|
// <Flex direction="column" align="stretch" gap="2">
|
|
// <TextField.Root
|
|
// value={input}
|
|
// onChange={e => setInput(e.target.value)}
|
|
// />
|
|
|
|
// <VMemoizedAsyncComponent />
|
|
// <VAsyncComponent />
|
|
// </Flex>
|
|
// ),
|
|
// ).pipe(
|
|
// Component.withRuntime(runtime.context)
|
|
// )
|
|
|
|
|
|
class AsyncComponent extends Component.makeUntraced("AsyncComponent")(function*() {
|
|
const SubComponentFC = yield* SubComponent
|
|
|
|
yield* Effect.sleep("500 millis") // Async operation
|
|
// Cannot use React hooks after the async operation
|
|
|
|
return (
|
|
<Flex direction="column" align="stretch">
|
|
<Text>Rendered!</Text>
|
|
<SubComponentFC />
|
|
</Flex>
|
|
)
|
|
}).pipe(
|
|
Async.async,
|
|
Async.withOptions({ defaultFallback: <p>Loading...</p> }),
|
|
) {}
|
|
class MemoizedAsyncComponent extends Memoized.memoized(AsyncComponent) {}
|
|
|
|
class SubComponent extends Component.makeUntraced("SubComponent")(function*() {
|
|
const [state] = React.useState(yield* Hooks.useOnce(() => Effect.provide(makeUuid4, GetRandomValues.CryptoRandom)))
|
|
return <Text>{state}</Text>
|
|
}) {}
|
|
|
|
export const Route = createFileRoute("/dev/async-rendering")({
|
|
component: RouteComponent
|
|
})
|