Add explicit lifecycle pipelines and scheduled query refreshes (#68)
## Summary
- Replace auto-running `service` constructors with explicit `make(...).pipe(thenRun)` lifecycle pipelines.
- Add scoped, schedule-driven Query refreshes with `Query.withScheduledRefresh`.
- Upgrade the Effect v4 stack to beta 102.
- Add `@effect-view/vite-plugin` to the publish workflow.
- Update examples and documentation for the new APIs.
## Breaking changes
The following constructors have been replaced:
- `Query.service(options)` → `Query.make(options).pipe(Query.thenRun)`
- `QueryClient.service(options)` → `QueryClient.make(options).pipe(QueryClient.thenRun)`
- `MutationForm.service(options)` → `MutationForm.make(options).pipe(MutationForm.thenRun)`
- `LensForm.service(options)` → `LensForm.make(options).pipe(LensForm.thenRun)`
This separates object construction from starting its scoped background behavior.
## Scheduled Query refreshes
Queries can now be refreshed with any Effect `Schedule`:
```ts
const query = yield* Query.make(options).pipe(
Query.thenRun,
Query.withScheduledRefresh(Schedule.spaced("5 minutes")),
)
---------
Co-authored-by: Julien Valverdé <julien.valverde@mailo.com>
Reviewed-on: #68
This commit was merged in pull request #68.
This commit is contained in:
@@ -26,11 +26,13 @@ const RegisterRouteComponent = Component.make("RegisterRouteView")(function*() {
|
||||
}))
|
||||
|
||||
const [form, emailField, passwordField] = yield* Component.useOnMount(() => Effect.gen(function*() {
|
||||
const form = yield* MutationForm.service({
|
||||
const form = yield* MutationForm.make({
|
||||
schema: RegisterSchema,
|
||||
initialEncodedValue: { email: "", password: "" },
|
||||
f: ([value]) => Effect.log(`Registered ${value.email}`),
|
||||
})
|
||||
}).pipe(
|
||||
MutationForm.thenRun,
|
||||
)
|
||||
|
||||
const emailField = Form.focusObjectOn(form, "email")
|
||||
const passwordField = Form.focusObjectOn(form, "password")
|
||||
|
||||
@@ -65,14 +65,16 @@ const UserProfileEditorView = Component.make("UserProfileEditorView")(function*(
|
||||
Stream.runForEach(Lens.changes(appState.lens), Console.log)
|
||||
)
|
||||
|
||||
const form = yield* LensForm.service({
|
||||
const form = yield* LensForm.make({
|
||||
schema: UserProfileSchema,
|
||||
target: Lens.focusObjectOn(appState.lens, "currentUser"),
|
||||
initialEncodedValue: {
|
||||
email: "",
|
||||
password: "",
|
||||
},
|
||||
})
|
||||
}).pipe(
|
||||
LensForm.thenRun,
|
||||
)
|
||||
|
||||
const emailField = Form.focusObjectOn(form, "email")
|
||||
const passwordField = Form.focusObjectOn(form, "password")
|
||||
|
||||
@@ -36,16 +36,18 @@ const QueryRouteComponent = Component.make("QueryRouteView")(function*() {
|
||||
const keyLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(["post", 1 as number] as const))
|
||||
const idLens = Lens.focusTupleAt(keyLens, 1)
|
||||
|
||||
const query = yield* Query.service({
|
||||
const query = yield* Query.make({
|
||||
key: keyLens,
|
||||
f: ([, id]) => HttpClient.HttpClient.pipe(
|
||||
Effect.tap(Effect.sleep("1 second")),
|
||||
Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)),
|
||||
Effect.andThen(response => response.json),
|
||||
Effect.andThen(Schema.decodeUnknownEffect(Post)),
|
||||
Effect.tap(Effect.sleep("500 millis")),
|
||||
Effect.flatMap(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)),
|
||||
Effect.flatMap(response => response.json),
|
||||
Effect.flatMap(Schema.decodeUnknownEffect(Post)),
|
||||
),
|
||||
staleTime: "10 seconds",
|
||||
})
|
||||
}).pipe(
|
||||
Query.thenRun,
|
||||
)
|
||||
|
||||
const mutation = yield* Mutation.make({
|
||||
f: ([id]: [id: number]) => HttpClient.HttpClient.pipe(
|
||||
|
||||
Reference in New Issue
Block a user