@raf-query/react 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -1
- package/README.md +32 -59
- package/dist/bind.d.mts +21 -0
- package/dist/bind.mjs +23 -0
- package/dist/browser-render.mjs +46 -0
- package/dist/devtools.d.mts +42 -2
- package/dist/devtools.mjs +244 -1
- package/dist/hydration-boundary/hydrate.mjs +10 -13
- package/dist/hydration-boundary/hydration-boundary-react-server.d.mts +6 -0
- package/dist/hydration-boundary/hydration-boundary-react-server.mjs +20 -9
- package/dist/hydration-boundary/hydration-boundary.d.mts +15 -28
- package/dist/hydration-boundary/hydration-boundary.mjs +7 -26
- package/dist/index-react-server.d.mts +7 -6
- package/dist/index-react-server.mjs +4 -6
- package/dist/index-shared.d.mts +5 -6
- package/dist/index-shared.mjs +3 -6
- package/dist/index.d.mts +7 -6
- package/dist/index.mjs +5 -4
- package/dist/provider.d.mts +11 -5
- package/dist/provider.mjs +12 -9
- package/dist/react-server-hooks.d.mts +43 -0
- package/dist/react-server-hooks.mjs +45 -0
- package/dist/tanstack-router-browser.d.mts +2 -0
- package/dist/tanstack-router-browser.mjs +2 -0
- package/dist/tanstack-router-shared.d.mts +9 -7
- package/dist/tanstack-router-shared.mjs +12 -22
- package/dist/tanstack-router.d.mts +4 -2
- package/dist/tanstack-router.mjs +12 -14
- package/dist/tracked.d.mts +1 -0
- package/dist/tracked.mjs +65 -0
- package/dist/use-infinite-query.d.mts +23 -0
- package/dist/use-infinite-query.mjs +30 -0
- package/dist/use-is-fetching.d.mts +7 -15
- package/dist/use-is-fetching.mjs +12 -30
- package/dist/use-query.d.mts +52 -50
- package/dist/use-query.mjs +112 -47
- package/package.json +10 -9
- package/dist/devtools-panel.d.mts +0 -38
- package/dist/devtools-panel.mjs +0 -896
- package/dist/devtools-store.mjs +0 -104
- package/dist/hydration-boundary/sent.mjs +0 -16
- package/dist/query-provider/browser-requests.mjs +0 -38
- package/dist/query-provider/query-provider.d.mts +0 -21
- package/dist/query-provider/query-provider.mjs +0 -33
- package/dist/use-waterfall.d.mts +0 -18
- package/dist/use-waterfall.mjs +0 -41
package/dist/devtools-store.mjs
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { Query } from "@raf-query/core";
|
|
2
|
-
import { useSyncExternalStore } from "react";
|
|
3
|
-
//#region src/devtools-store.ts
|
|
4
|
-
const statuses = [
|
|
5
|
-
"fetching",
|
|
6
|
-
"error",
|
|
7
|
-
"stale",
|
|
8
|
-
"fresh",
|
|
9
|
-
"inactive"
|
|
10
|
-
];
|
|
11
|
-
const sortOrders = [
|
|
12
|
-
"status",
|
|
13
|
-
"hash",
|
|
14
|
-
"updated"
|
|
15
|
-
];
|
|
16
|
-
const stores = /* @__PURE__ */ new WeakMap();
|
|
17
|
-
function statusOf(query) {
|
|
18
|
-
const state = Query.getUnsafe(query);
|
|
19
|
-
if (state.isFetching) return "fetching";
|
|
20
|
-
if (state.status === "error") return "error";
|
|
21
|
-
if (Query.observerCountUnsafe(query) === 0) return "inactive";
|
|
22
|
-
return Query.isStaleUnsafe(query) ? "stale" : "fresh";
|
|
23
|
-
}
|
|
24
|
-
function rowOf(query) {
|
|
25
|
-
return {
|
|
26
|
-
hash: query.hash,
|
|
27
|
-
observers: Query.observerCountUnsafe(query),
|
|
28
|
-
query,
|
|
29
|
-
state: Query.getUnsafe(query),
|
|
30
|
-
status: statusOf(query)
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function createStore(client) {
|
|
34
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
35
|
-
let version = 0;
|
|
36
|
-
let snapshotVersion = -1;
|
|
37
|
-
let snapshot = [];
|
|
38
|
-
let scheduled = false;
|
|
39
|
-
client.subscribe(() => {
|
|
40
|
-
version++;
|
|
41
|
-
if (scheduled || listeners.size === 0) return;
|
|
42
|
-
scheduled = true;
|
|
43
|
-
queueMicrotask(() => {
|
|
44
|
-
scheduled = false;
|
|
45
|
-
for (const listener of listeners) listener();
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
return {
|
|
49
|
-
getSnapshot: () => {
|
|
50
|
-
if (snapshotVersion !== version) {
|
|
51
|
-
snapshotVersion = version;
|
|
52
|
-
snapshot = client.getAll().map(rowOf);
|
|
53
|
-
}
|
|
54
|
-
return snapshot;
|
|
55
|
-
},
|
|
56
|
-
subscribe: (onChange) => {
|
|
57
|
-
listeners.add(onChange);
|
|
58
|
-
return () => {
|
|
59
|
-
listeners.delete(onChange);
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
function storeFor(client) {
|
|
65
|
-
let store = stores.get(client);
|
|
66
|
-
if (!store) {
|
|
67
|
-
store = createStore(client);
|
|
68
|
-
stores.set(client, store);
|
|
69
|
-
}
|
|
70
|
-
return store;
|
|
71
|
-
}
|
|
72
|
-
/** Every cache entry, re-rendering on each batch of cache events. */
|
|
73
|
-
function useQueryRows(client) {
|
|
74
|
-
const store = storeFor(client);
|
|
75
|
-
return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
76
|
-
}
|
|
77
|
-
function countByStatus(rows) {
|
|
78
|
-
const counts = {
|
|
79
|
-
error: 0,
|
|
80
|
-
fetching: 0,
|
|
81
|
-
fresh: 0,
|
|
82
|
-
inactive: 0,
|
|
83
|
-
stale: 0
|
|
84
|
-
};
|
|
85
|
-
for (const row of rows) counts[row.status]++;
|
|
86
|
-
return counts;
|
|
87
|
-
}
|
|
88
|
-
function compareRows(sortBy) {
|
|
89
|
-
return (a, b) => {
|
|
90
|
-
const primary = {
|
|
91
|
-
hash: 0,
|
|
92
|
-
status: statuses.indexOf(a.status) - statuses.indexOf(b.status),
|
|
93
|
-
updated: b.state.updatedAt - a.state.updatedAt
|
|
94
|
-
}[sortBy];
|
|
95
|
-
return primary === 0 ? a.hash.localeCompare(b.hash) : primary;
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/** Rows whose hash contains `filter` (case-insensitive), sorted. */
|
|
99
|
-
function visibleRows(rows, filter, sortBy) {
|
|
100
|
-
const needle = filter.trim().toLowerCase();
|
|
101
|
-
return rows.filter((row) => row.hash.toLowerCase().includes(needle)).toSorted(compareRows(sortBy));
|
|
102
|
-
}
|
|
103
|
-
//#endregion
|
|
104
|
-
export { countByStatus, sortOrders, statuses, useQueryRows, visibleRows };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
//#region src/hydration-boundary/sent.ts
|
|
2
|
-
const sentByClient = /* @__PURE__ */ new WeakMap();
|
|
3
|
-
/**
|
|
4
|
-
* Hashes of the request client's entries an earlier `HydrationBoundary`
|
|
5
|
-
* already sent. Boundaries pass it as `sent`, so each entry crosses once.
|
|
6
|
-
*/
|
|
7
|
-
function sentHashes(client) {
|
|
8
|
-
let sent = sentByClient.get(client);
|
|
9
|
-
if (!sent) {
|
|
10
|
-
sent = /* @__PURE__ */ new Set();
|
|
11
|
-
sentByClient.set(client, sent);
|
|
12
|
-
}
|
|
13
|
-
return sent;
|
|
14
|
-
}
|
|
15
|
-
//#endregion
|
|
16
|
-
export { sentHashes };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Query } from "@raf-query/core";
|
|
2
|
-
//#region src/query-provider/browser-requests.ts
|
|
3
|
-
/**
|
|
4
|
-
* The digest Next.js gives a boundary that renders only in the browser
|
|
5
|
-
* (`next/dynamic` with `ssr: false`); it doesn't report those errors.
|
|
6
|
-
*/
|
|
7
|
-
const clientRendering = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
|
|
8
|
-
const browserOnly = /* @__PURE__ */ new WeakSet();
|
|
9
|
-
/**
|
|
10
|
-
* Make a server client's render start no request: it reads what a
|
|
11
|
-
* `HydrationBoundary` sent, and anything else loads in the browser.
|
|
12
|
-
*/
|
|
13
|
-
function requestInBrowserOnly(client) {
|
|
14
|
-
browserOnly.add(client);
|
|
15
|
-
}
|
|
16
|
-
/** Whether a render may start `client`'s requests (`useWaterfall`). */
|
|
17
|
-
function startsRequests(client) {
|
|
18
|
-
return !(client.isServer && browserOnly.has(client));
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Thrown by a server render's read of a query no `HydrationBoundary` sent.
|
|
22
|
-
* React renders the nearest Suspense fallback, and the browser renders the
|
|
23
|
-
* content.
|
|
24
|
-
*/
|
|
25
|
-
var BrowserRenderError = class extends Error {
|
|
26
|
-
digest = clientRendering;
|
|
27
|
-
constructor(hash) {
|
|
28
|
-
super(`Query ${hash} loads in the browser: no HydrationBoundary sent it`);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
/** Throw {@link BrowserRenderError} if reading `query` would start a request here. */
|
|
32
|
-
function assertSent(client, query) {
|
|
33
|
-
if (startsRequests(client)) return;
|
|
34
|
-
const state = Query.getUnsafe(query);
|
|
35
|
-
if (!state.hasData && !state.isFetching && state.status !== "error") throw new BrowserRenderError(query.hash);
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
|
-
export { assertSent, requestInBrowserOnly, startsRequests };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { QueryClientConfig } from "@raf-query/core";
|
|
2
|
-
import { ReactNode } from "react";
|
|
3
|
-
//#region src/query-provider/query-provider.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* The query client provider for React Server Components apps. Creates one
|
|
6
|
-
* client per server render and one per browser tab. The server render
|
|
7
|
-
* starts no request: client components read what `HydrationBoundary` sent,
|
|
8
|
-
* and a query nothing sent renders its Suspense fallback there and loads in
|
|
9
|
-
* the browser.
|
|
10
|
-
*
|
|
11
|
-
* ```tsx
|
|
12
|
-
* // app/layout.tsx
|
|
13
|
-
* <QueryProvider>{props.children}</QueryProvider>
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
export declare function QueryProvider(props: {
|
|
17
|
-
readonly children?: ReactNode;
|
|
18
|
-
/** Options for the client it creates. */
|
|
19
|
-
readonly config?: QueryClientConfig;
|
|
20
|
-
}): import("react").JSX.Element;
|
|
21
|
-
//#endregion
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { QueryClientProvider } from "../provider.mjs";
|
|
3
|
-
import { requestInBrowserOnly } from "./browser-requests.mjs";
|
|
4
|
-
import { QueryClient } from "@raf-query/core";
|
|
5
|
-
import { useState } from "react";
|
|
6
|
-
import { jsx } from "react/jsx-runtime";
|
|
7
|
-
//#region src/query-provider/query-provider.tsx
|
|
8
|
-
/**
|
|
9
|
-
* The query client provider for React Server Components apps. Creates one
|
|
10
|
-
* client per server render and one per browser tab. The server render
|
|
11
|
-
* starts no request: client components read what `HydrationBoundary` sent,
|
|
12
|
-
* and a query nothing sent renders its Suspense fallback there and loads in
|
|
13
|
-
* the browser.
|
|
14
|
-
*
|
|
15
|
-
* ```tsx
|
|
16
|
-
* // app/layout.tsx
|
|
17
|
-
* <QueryProvider>{props.children}</QueryProvider>
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
function QueryProvider(props) {
|
|
21
|
-
const config = props.config;
|
|
22
|
-
const [client] = useState(() => {
|
|
23
|
-
const created = new QueryClient(config);
|
|
24
|
-
requestInBrowserOnly(created);
|
|
25
|
-
return created;
|
|
26
|
-
});
|
|
27
|
-
return /* @__PURE__ */ jsx(QueryClientProvider, {
|
|
28
|
-
client,
|
|
29
|
-
children: props.children
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
|
-
export { QueryProvider };
|
package/dist/use-waterfall.d.mts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { InputArgs, QueryFactory, QueryHandle } from "@raf-query/core";
|
|
2
|
-
//#region src/use-waterfall.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Start a query during render and return its handle, for inputs only known
|
|
5
|
-
* at render time (an id from a parent query's data). Each call is a request
|
|
6
|
-
* waterfall: prefer starting the query in a loader or server component.
|
|
7
|
-
* Like `prefetch` in a loader, it refetches stale cached data in the
|
|
8
|
-
* background, once per mount and input. Under `QueryProvider` it
|
|
9
|
-
* starts nothing on the server: the reader's Suspense boundary renders its
|
|
10
|
-
* fallback there, and the query loads in the browser.
|
|
11
|
-
*
|
|
12
|
-
* ```tsx
|
|
13
|
-
* const author = useWaterfall(authorQuery, { id: post.authorId });
|
|
14
|
-
* const [authorPromise] = useQuery(authorQuery, author);
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
export declare function useWaterfall<TFactory extends QueryFactory>(factory: TFactory, ...args: InputArgs<TFactory>): QueryHandle<TFactory>;
|
|
18
|
-
//#endregion
|
package/dist/use-waterfall.mjs
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useQueryClient } from "./provider.mjs";
|
|
3
|
-
import { startsRequests } from "./query-provider/browser-requests.mjs";
|
|
4
|
-
import { Query } from "@raf-query/core";
|
|
5
|
-
import { useState } from "react";
|
|
6
|
-
//#region src/use-waterfall.ts
|
|
7
|
-
/**
|
|
8
|
-
* First loads a waterfall suspended on. A suspended mount keeps no state, so
|
|
9
|
-
* this is how its retry knows the data it finds is the load it just waited
|
|
10
|
-
* for, not cached data to revalidate.
|
|
11
|
-
*/
|
|
12
|
-
const waitedFor = /* @__PURE__ */ new WeakSet();
|
|
13
|
-
/**
|
|
14
|
-
* Start a query during render and return its handle, for inputs only known
|
|
15
|
-
* at render time (an id from a parent query's data). Each call is a request
|
|
16
|
-
* waterfall: prefer starting the query in a loader or server component.
|
|
17
|
-
* Like `prefetch` in a loader, it refetches stale cached data in the
|
|
18
|
-
* background, once per mount and input. Under `QueryProvider` it
|
|
19
|
-
* starts nothing on the server: the reader's Suspense boundary renders its
|
|
20
|
-
* fallback there, and the query loads in the browser.
|
|
21
|
-
*
|
|
22
|
-
* ```tsx
|
|
23
|
-
* const author = useWaterfall(authorQuery, { id: post.authorId });
|
|
24
|
-
* const [authorPromise] = useQuery(authorQuery, author);
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
function useWaterfall(factory, ...args) {
|
|
28
|
-
const client = useQueryClient();
|
|
29
|
-
const query = client.getQuery(factory, ...args);
|
|
30
|
-
const [started, setStarted] = useState();
|
|
31
|
-
if (!startsRequests(client)) return query.handle;
|
|
32
|
-
const promise = Query.readUnsafe(query);
|
|
33
|
-
if (started !== query.hash) {
|
|
34
|
-
if (!Query.getUnsafe(query).hasData) waitedFor.add(promise);
|
|
35
|
-
else if (!waitedFor.delete(promise)) Query.revalidateUnsafe(query);
|
|
36
|
-
setStarted(query.hash);
|
|
37
|
-
} else if (Query.getUnsafe(query).hasData) waitedFor.delete(promise);
|
|
38
|
-
return query.handle;
|
|
39
|
-
}
|
|
40
|
-
//#endregion
|
|
41
|
-
export { useWaterfall };
|