diff --git a/bun.lock b/bun.lock
index 14fcfe5..9ead317 100644
--- a/bun.lock
+++ b/bun.lock
@@ -58,9 +58,23 @@
"reffuse": "^0.1.1",
},
},
+ "packages/extension-query": {
+ "name": "@reffuse/extension-query",
+ "version": "0.1.0",
+ "devDependencies": {
+ "reffuse": "workspace:*",
+ },
+ "peerDependencies": {
+ "@typed/async-data": "^0.13.1",
+ "@types/react": "^19.0.0",
+ "effect": "^3.13.0",
+ "react": "^19.0.0",
+ "reffuse": "^0.1.2",
+ },
+ },
"packages/reffuse": {
"name": "reffuse",
- "version": "0.1.1",
+ "version": "0.1.2",
"peerDependencies": {
"@types/react": "^19.0.0",
"effect": "^3.13.0",
@@ -333,6 +347,8 @@
"@reffuse/extension-lazyref": ["@reffuse/extension-lazyref@workspace:packages/extension-lazyref"],
+ "@reffuse/extension-query": ["@reffuse/extension-query@workspace:packages/extension-query"],
+
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="],
@@ -395,6 +411,8 @@
"@thilawyn/thilaschema": ["@thilawyn/thilaschema@0.1.4", "https://git.valverde.cloud/api/packages/Thilawyn/npm/%40thilawyn%2Fthilaschema/-/0.1.4/thilaschema-0.1.4.tgz", { "dependencies": { "remeda": "^2.17.0", "type-fest": "^4.26.1" } }, "sha512-o+lFjnRrD8N7kJtToKl+OYvVnOwaCGr1X9yMSX/8Y1n4KopOOGFSA9xqmx+MpMe3okp2Hq3Xu1aGHzFsZWxc2A=="],
+ "@typed/async-data": ["@typed/async-data@0.13.1", "", { "dependencies": { "@typed/lazy-ref": "^0.3.2", "effect": "^3.11.9" } }, "sha512-rKv3HQtoHeGJwZpEaTL0FAEKfqHcMr/x3GtgkE01p2tJiKjq1eVaPZYpweZEEF/zUutox7DQ14oH85x+ZpPA/Q=="],
+
"@typed/id": ["@typed/id@0.17.1", "", { "dependencies": { "effect": "^3.11.9" } }, "sha512-+nypUUw6PJWePD1aF1CHY4995hDF3VA9c8EBtp1M+pTnyLBZQIkgKbOKamimnl4U+ZV5I3qC+3q1Y4hpmxT+zw=="],
"@typed/lazy-ref": ["@typed/lazy-ref@0.3.3", "", { "dependencies": { "effect": "^3.11.9" } }, "sha512-qJoy01/RFYwWBaWhQBzL3Ow20Q+CPybJ/KJnGNKzyDpRUFcEvd3YSQMqZjRdBZmG2wnEpjedAnlCx9ApvKJIlA=="],
diff --git a/packages/extension-query/package.json b/packages/extension-query/package.json
index 10b1b4f..d50650c 100644
--- a/packages/extension-query/package.json
+++ b/packages/extension-query/package.json
@@ -33,6 +33,7 @@
"reffuse": "workspace:*"
},
"peerDependencies": {
+ "@typed/async-data": "^0.13.1",
"@types/react": "^19.0.0",
"effect": "^3.13.0",
"react": "^19.0.0",
diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts
index e5fbb02..ebd3518 100644
--- a/packages/extension-query/src/index.ts
+++ b/packages/extension-query/src/index.ts
@@ -1,29 +1,35 @@
-import * as LazyRef from "@typed/lazy-ref"
-import { Effect, Stream } from "effect"
+import * as AsyncData from "@typed/async-data"
+import { Effect } from "effect"
import * as React from "react"
-import { ReffuseExtension, type ReffuseHelpers, SetStateAction } from "reffuse"
+import { useState } from "react"
+import { ReffuseExtension, type ReffuseHelpers } from "reffuse"
-export const LazyRefExtension = ReffuseExtension.make(() => ({
- useLazyRefState(
+export interface UseQueryProps {
+ effect(): Effect.Effect
+ readonly deps?: React.DependencyList
+}
+
+export interface UseQueryResult {
+ readonly state: AsyncData.AsyncData
+}
+
+
+export const QueryExtension = ReffuseExtension.make(() => ({
+ useQuery(
this: ReffuseHelpers.ReffuseHelpers,
- ref: LazyRef.LazyRef,
- ): [A, React.Dispatch>] {
- const runSync = this.useRunSync()
+ props: UseQueryProps,
+ ): UseQueryResult {
+ const [state, setState] = useState(AsyncData.noData())
- const initialState = React.useMemo(() => runSync(ref), [])
- const [reactStateValue, setReactStateValue] = React.useState(initialState)
+ this.useFork(() => Effect.sync(() => setState(AsyncData.loading())).pipe(
+ Effect.andThen(props.effect()),
+ Effect.matchCause({
+ onSuccess: v => setState(AsyncData.success(v)),
+ onFailure: c => setState(AsyncData.failure(c)),
+ }),
+ ), props.deps)
- this.useFork(() => Stream.runForEach(ref.changes, v => Effect.sync(() =>
- setReactStateValue(v)
- )), [ref])
-
- const setValue = React.useCallback((setStateAction: React.SetStateAction) =>
- runSync(LazyRef.update(ref, prevState =>
- SetStateAction.value(setStateAction, prevState)
- )),
- [ref])
-
- return [reactStateValue, setValue]
- },
+ return { state }
+ }
}))