Add Effect v4 support, Fast Refresh tooling, and revamped docs #56
@@ -15,7 +15,6 @@ import { Route as BlankRouteImport } from './routes/blank'
|
|||||||
import { Route as FormRouteImport } from './routes/form'
|
import { Route as FormRouteImport } from './routes/form'
|
||||||
import { Route as LensformRouteImport } from './routes/lensform'
|
import { Route as LensformRouteImport } from './routes/lensform'
|
||||||
import { Route as QueryRouteImport } from './routes/query'
|
import { Route as QueryRouteImport } from './routes/query'
|
||||||
import { Route as ResultRouteImport } from './routes/result'
|
|
||||||
|
|
||||||
const IndexRoute = IndexRouteImport.update({
|
const IndexRoute = IndexRouteImport.update({
|
||||||
id: '/',
|
id: '/',
|
||||||
@@ -47,11 +46,6 @@ const QueryRoute = QueryRouteImport.update({
|
|||||||
path: '/query',
|
path: '/query',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
const ResultRoute = ResultRouteImport.update({
|
|
||||||
id: '/result',
|
|
||||||
path: '/result',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
@@ -60,7 +54,6 @@ export interface FileRoutesByFullPath {
|
|||||||
'/form': typeof FormRoute
|
'/form': typeof FormRoute
|
||||||
'/lensform': typeof LensformRoute
|
'/lensform': typeof LensformRoute
|
||||||
'/query': typeof QueryRoute
|
'/query': typeof QueryRoute
|
||||||
'/result': typeof ResultRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
@@ -69,7 +62,6 @@ export interface FileRoutesByTo {
|
|||||||
'/form': typeof FormRoute
|
'/form': typeof FormRoute
|
||||||
'/lensform': typeof LensformRoute
|
'/lensform': typeof LensformRoute
|
||||||
'/query': typeof QueryRoute
|
'/query': typeof QueryRoute
|
||||||
'/result': typeof ResultRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
@@ -79,23 +71,13 @@ export interface FileRoutesById {
|
|||||||
'/form': typeof FormRoute
|
'/form': typeof FormRoute
|
||||||
'/lensform': typeof LensformRoute
|
'/lensform': typeof LensformRoute
|
||||||
'/query': typeof QueryRoute
|
'/query': typeof QueryRoute
|
||||||
'/result': typeof ResultRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths:
|
fullPaths: '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query'
|
||||||
'/' | '/async' | '/blank' | '/form' | '/lensform' | '/query' | '/result'
|
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to: '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query' | '/result'
|
to: '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query'
|
||||||
id:
|
id: '__root__' | '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query'
|
||||||
| '__root__'
|
|
||||||
| '/'
|
|
||||||
| '/async'
|
|
||||||
| '/blank'
|
|
||||||
| '/form'
|
|
||||||
| '/lensform'
|
|
||||||
| '/query'
|
|
||||||
| '/result'
|
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
@@ -105,7 +87,6 @@ export interface RootRouteChildren {
|
|||||||
FormRoute: typeof FormRoute
|
FormRoute: typeof FormRoute
|
||||||
LensformRoute: typeof LensformRoute
|
LensformRoute: typeof LensformRoute
|
||||||
QueryRoute: typeof QueryRoute
|
QueryRoute: typeof QueryRoute
|
||||||
ResultRoute: typeof ResultRoute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
@@ -152,13 +133,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof QueryRouteImport
|
preLoaderRoute: typeof QueryRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
'/result': {
|
|
||||||
id: '/result'
|
|
||||||
path: '/result'
|
|
||||||
fullPath: '/result'
|
|
||||||
preLoaderRoute: typeof ResultRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +143,6 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
FormRoute: FormRoute,
|
FormRoute: FormRoute,
|
||||||
LensformRoute: LensformRoute,
|
LensformRoute: LensformRoute,
|
||||||
QueryRoute: QueryRoute,
|
QueryRoute: QueryRoute,
|
||||||
ResultRoute: ResultRoute,
|
|
||||||
}
|
}
|
||||||
export const routeTree = rootRouteImport
|
export const routeTree = rootRouteImport
|
||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ function Root() {
|
|||||||
<Link to="/blank">Blank</Link>
|
<Link to="/blank">Blank</Link>
|
||||||
<Link to="/async">Async</Link>
|
<Link to="/async">Async</Link>
|
||||||
<Link to="/query">Query</Link>
|
<Link to="/query">Query</Link>
|
||||||
<Link to="/result">Result</Link>
|
|
||||||
<Link to="/form">Form</Link>
|
<Link to="/form">Form</Link>
|
||||||
<Link to="/lensform">LensForm</Link>
|
<Link to="/lensform">LensForm</Link>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
import { Container, Flex, Heading, Slider, Text, TextField } from "@radix-ui/themes"
|
import { Container, Flex, Heading, Slider, Text, TextField } from "@radix-ui/themes"
|
||||||
import { createFileRoute } from "@tanstack/react-router"
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
|
import { Console, Effect } from "effect"
|
||||||
import { Async, Component, Memoized } from "effect-fc-next"
|
import { Async, Component, Memoized } from "effect-fc-next"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { fetchPost } from "@/post"
|
|
||||||
import { runtime } from "@/runtime"
|
import { runtime } from "@/runtime"
|
||||||
|
|
||||||
|
|
||||||
|
const fetchPost = (id: number) => Effect.sleep("500 millis").pipe(
|
||||||
|
Effect.as({
|
||||||
|
title: `Post ${id}`,
|
||||||
|
body: `This is the content of post ${id}.`,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
interface AsyncFetchPostViewProps {
|
interface AsyncFetchPostViewProps {
|
||||||
readonly id: number
|
readonly id: number
|
||||||
}
|
}
|
||||||
@@ -13,6 +21,11 @@ interface AsyncFetchPostViewProps {
|
|||||||
const AsyncFetchPostView = Component.make("AsyncFetchPostView")(function*(
|
const AsyncFetchPostView = Component.make("AsyncFetchPostView")(function*(
|
||||||
props: AsyncFetchPostViewProps,
|
props: AsyncFetchPostViewProps,
|
||||||
) {
|
) {
|
||||||
|
yield* Component.useOnMount(() => Effect.gen(function*() {
|
||||||
|
yield* Effect.addFinalizer(() => Console.log("AsyncFetchPostView unmounted"))
|
||||||
|
yield* Console.log("AsyncFetchPostView mounted")
|
||||||
|
}))
|
||||||
|
|
||||||
const post = yield* Component.useOnChange(
|
const post = yield* Component.useOnChange(
|
||||||
() => fetchPost(props.id),
|
() => fetchPost(props.id),
|
||||||
[props.id],
|
[props.id],
|
||||||
@@ -51,7 +64,7 @@ const AsyncRouteComponent = Component.make("AsyncRouteView")(function*() {
|
|||||||
onValueChange={([value]) => setId(value ?? 1)}
|
onValueChange={([value]) => setId(value ?? 1)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AsyncFetchPost id={id} fallback={<Text>Loading post...</Text>} />
|
<AsyncFetchPost id={id} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
import { Button, Container, Flex, Heading, Text } from "@radix-ui/themes"
|
|
||||||
import { createFileRoute } from "@tanstack/react-router"
|
|
||||||
import { AsyncResult } from "effect/unstable/reactivity"
|
|
||||||
import { Component, Mutation, View } from "effect-fc-next"
|
|
||||||
import { fetchPost, type Post } from "@/post"
|
|
||||||
import { runtime } from "@/runtime"
|
|
||||||
|
|
||||||
|
|
||||||
const PostResultView = (props: { readonly result: AsyncResult.AsyncResult<Post, Error> }) =>
|
|
||||||
AsyncResult.match(props.result, {
|
|
||||||
onInitial: () => <Text>Ready to load.</Text>,
|
|
||||||
onFailure: () => <Text>Request failed.</Text>,
|
|
||||||
onSuccess: result => (
|
|
||||||
<>
|
|
||||||
<Heading>{result.value.title}</Heading>
|
|
||||||
<Text>{result.value.body}</Text>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
})
|
|
||||||
|
|
||||||
const ResultRouteComponent = Component.make("ResultRouteView")(function*() {
|
|
||||||
const mutation = yield* Component.useOnMount(() => Mutation.make({
|
|
||||||
f: (_: undefined) => fetchPost(1),
|
|
||||||
}))
|
|
||||||
const [result] = yield* View.useAll([mutation.state])
|
|
||||||
const runPromise = yield* Component.useRunPromise()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
<Button onClick={() => void runPromise(mutation.mutate(undefined))}>
|
|
||||||
Load post
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<PostResultView result={result} />
|
|
||||||
</Flex>
|
|
||||||
</Container>
|
|
||||||
)
|
|
||||||
}).pipe(
|
|
||||||
Component.withContext(runtime.context),
|
|
||||||
)
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/result")({
|
|
||||||
component: ResultRouteComponent,
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user