@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
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
import { Hydrate } from "./hydrate.mjs";
|
|
2
|
-
import { sentHashes } from "./sent.mjs";
|
|
3
2
|
import { dehydrate } from "@raf-query/core";
|
|
4
3
|
import { jsx } from "react/jsx-runtime";
|
|
5
4
|
//#region src/hydration-boundary/hydration-boundary-react-server.tsx
|
|
5
|
+
const sentByClient = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
/**
|
|
7
|
+
* Hashes of the request client's entries an earlier `HydrationBoundary`
|
|
8
|
+
* already sent, so each entry crosses once per request.
|
|
9
|
+
*/
|
|
10
|
+
function sentHashes(client) {
|
|
11
|
+
const sent = sentByClient.get(client) ?? /* @__PURE__ */ new Set();
|
|
12
|
+
sentByClient.set(client, sent);
|
|
13
|
+
return sent;
|
|
14
|
+
}
|
|
6
15
|
/**
|
|
7
16
|
* `HydrationBoundary` in server components (the `react-server` export
|
|
8
17
|
* condition). With `client`, sends the request client's entries to the
|
|
9
18
|
* browser cache: pending entries cross as promises and stream in as they
|
|
10
19
|
* settle, and entries an earlier boundary already sent in this request are
|
|
11
20
|
* skipped. With `state`, writes that state, as the browser version does.
|
|
21
|
+
*
|
|
22
|
+
* It also marks the client components' server render: from there on, a read
|
|
23
|
+
* of a query nothing sent renders its Suspense fallback on the server and
|
|
24
|
+
* loads in the browser, instead of fetching where nothing would send it.
|
|
25
|
+
*
|
|
26
|
+
* @see https://raf-query.katt.dev/docs/react-server-components#setup
|
|
12
27
|
*/
|
|
13
28
|
function HydrationBoundary(props) {
|
|
14
|
-
if (props.client === void 0) return /* @__PURE__ */ jsx(Hydrate, {
|
|
15
|
-
options: props.options,
|
|
16
|
-
state: props.state,
|
|
17
|
-
children: props.children
|
|
18
|
-
});
|
|
19
29
|
const client = props.client;
|
|
20
|
-
const state = dehydrate(client, {
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
const state = client === void 0 ? props.state : dehydrate(client, {
|
|
31
|
+
...props.options,
|
|
32
|
+
sent: sentHashes(client)
|
|
23
33
|
});
|
|
24
34
|
return /* @__PURE__ */ jsx(Hydrate, {
|
|
35
|
+
fromServerComponents: true,
|
|
25
36
|
state,
|
|
26
37
|
children: props.children
|
|
27
38
|
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { DehydrateOptions, DehydratedState,
|
|
1
|
+
import { DehydrateOptions, DehydratedState, QueryClient } from "@raf-query/core";
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
3
|
//#region src/hydration-boundary/hydration-boundary.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Props of {@link HydrationBoundary}: a dehydrated `state`, or in server components the request's `client`.
|
|
6
|
+
*
|
|
7
|
+
* @see https://raf-query.katt.dev/docs/react-router#server-loaders
|
|
8
|
+
*/
|
|
4
9
|
export type HydrationBoundaryProps = {
|
|
5
10
|
readonly children?: ReactNode;
|
|
6
11
|
/**
|
|
@@ -13,8 +18,8 @@ export type HydrationBoundaryProps = {
|
|
|
13
18
|
} | {
|
|
14
19
|
readonly children?: ReactNode;
|
|
15
20
|
readonly client?: never;
|
|
16
|
-
readonly options?:
|
|
17
|
-
/** A loader's `dehydrate(
|
|
21
|
+
readonly options?: never;
|
|
22
|
+
/** A loader's `dehydrate(client)`. */
|
|
18
23
|
readonly state: DehydratedState;
|
|
19
24
|
};
|
|
20
25
|
/**
|
|
@@ -27,38 +32,20 @@ export type HydrationBoundaryProps = {
|
|
|
27
32
|
* through the package's `react-server` export condition.
|
|
28
33
|
*
|
|
29
34
|
* ```tsx
|
|
30
|
-
* const
|
|
31
|
-
* const
|
|
35
|
+
* const client = getQueryClient();
|
|
36
|
+
* const [handles] = await load(client, { comments: prefetch(commentsQuery, { slug }) });
|
|
32
37
|
* return (
|
|
33
|
-
* <HydrationBoundary client={
|
|
34
|
-
* <Comments handle={comments} />
|
|
38
|
+
* <HydrationBoundary client={client}>
|
|
39
|
+
* <Comments handle={handles.comments} />
|
|
35
40
|
* </HydrationBoundary>
|
|
36
41
|
* );
|
|
37
42
|
* ```
|
|
38
43
|
*
|
|
39
44
|
* With loaders, such as React Router Framework Mode, pass the `state` the
|
|
40
|
-
* loader dehydrated
|
|
41
|
-
*
|
|
42
|
-
* ```tsx
|
|
43
|
-
* export async function loader(args: Route.LoaderArgs) {
|
|
44
|
-
* const qc = new QueryClient();
|
|
45
|
-
* const post = await qc.ensure(postQuery, { slug: args.params.slug });
|
|
46
|
-
* return { dehydratedState: dehydrate(qc), post };
|
|
47
|
-
* }
|
|
48
|
-
*
|
|
49
|
-
* export default function Page(props: Route.ComponentProps) {
|
|
50
|
-
* const { dehydratedState, post } = props.loaderData;
|
|
51
|
-
* return (
|
|
52
|
-
* <HydrationBoundary state={dehydratedState}>
|
|
53
|
-
* <Post handle={post} />
|
|
54
|
-
* </HydrationBoundary>
|
|
55
|
-
* );
|
|
56
|
-
* }
|
|
57
|
-
* ```
|
|
45
|
+
* loader dehydrated. Pending entries cross as promises when the framework's
|
|
46
|
+
* serializer supports them (React Router's Single Fetch does).
|
|
58
47
|
*
|
|
59
|
-
*
|
|
60
|
-
* supports them (React Router's Single Fetch does). Nested boundaries
|
|
61
|
-
* are fine: each only writes what its `state` holds.
|
|
48
|
+
* @see https://raf-query.katt.dev/docs/react-router#server-loaders
|
|
62
49
|
*/
|
|
63
50
|
export declare function HydrationBoundary(props: HydrationBoundaryProps): import("react").JSX.Element;
|
|
64
51
|
//#endregion
|
|
@@ -12,43 +12,24 @@ import { jsx } from "react/jsx-runtime";
|
|
|
12
12
|
* through the package's `react-server` export condition.
|
|
13
13
|
*
|
|
14
14
|
* ```tsx
|
|
15
|
-
* const
|
|
16
|
-
* const
|
|
15
|
+
* const client = getQueryClient();
|
|
16
|
+
* const [handles] = await load(client, { comments: prefetch(commentsQuery, { slug }) });
|
|
17
17
|
* return (
|
|
18
|
-
* <HydrationBoundary client={
|
|
19
|
-
* <Comments handle={comments} />
|
|
18
|
+
* <HydrationBoundary client={client}>
|
|
19
|
+
* <Comments handle={handles.comments} />
|
|
20
20
|
* </HydrationBoundary>
|
|
21
21
|
* );
|
|
22
22
|
* ```
|
|
23
23
|
*
|
|
24
24
|
* With loaders, such as React Router Framework Mode, pass the `state` the
|
|
25
|
-
* loader dehydrated
|
|
25
|
+
* loader dehydrated. Pending entries cross as promises when the framework's
|
|
26
|
+
* serializer supports them (React Router's Single Fetch does).
|
|
26
27
|
*
|
|
27
|
-
*
|
|
28
|
-
* export async function loader(args: Route.LoaderArgs) {
|
|
29
|
-
* const qc = new QueryClient();
|
|
30
|
-
* const post = await qc.ensure(postQuery, { slug: args.params.slug });
|
|
31
|
-
* return { dehydratedState: dehydrate(qc), post };
|
|
32
|
-
* }
|
|
33
|
-
*
|
|
34
|
-
* export default function Page(props: Route.ComponentProps) {
|
|
35
|
-
* const { dehydratedState, post } = props.loaderData;
|
|
36
|
-
* return (
|
|
37
|
-
* <HydrationBoundary state={dehydratedState}>
|
|
38
|
-
* <Post handle={post} />
|
|
39
|
-
* </HydrationBoundary>
|
|
40
|
-
* );
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* Pending entries cross as promises when the framework's serializer
|
|
45
|
-
* supports them (React Router's Single Fetch does). Nested boundaries
|
|
46
|
-
* are fine: each only writes what its `state` holds.
|
|
28
|
+
* @see https://raf-query.katt.dev/docs/react-router#server-loaders
|
|
47
29
|
*/
|
|
48
30
|
function HydrationBoundary(props) {
|
|
49
31
|
if (props.state === void 0) throw new Error("HydrationBoundary needs `state` here. `client` works only in server components.");
|
|
50
32
|
return /* @__PURE__ */ jsx(Hydrate, {
|
|
51
|
-
options: props.options,
|
|
52
33
|
state: props.state,
|
|
53
34
|
children: props.children
|
|
54
35
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useWaterfall } from "./use-waterfall.mjs";
|
|
1
|
+
import { QueryDevtools, QueryDevtoolsPanel, QueryDevtoolsPanelProps, QueryDevtoolsProps } from "./devtools.mjs";
|
|
2
|
+
import { QueryClientProvider } from "./provider.mjs";
|
|
3
|
+
import { QueryState, QueryValue, UseQueryOptions } from "./use-query.mjs";
|
|
4
|
+
import { InfiniteQueryState } from "./use-infinite-query.mjs";
|
|
6
5
|
import "./index-shared.mjs";
|
|
6
|
+
import { HydrationBoundaryProps } from "./hydration-boundary/hydration-boundary.mjs";
|
|
7
7
|
import { HydrationBoundary } from "./hydration-boundary/hydration-boundary-react-server.mjs";
|
|
8
|
+
import { bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient } from "./react-server-hooks.mjs";
|
|
8
9
|
export * from "@raf-query/core";
|
|
9
|
-
export { HydrationBoundary, QueryClientProvider,
|
|
10
|
+
export { HydrationBoundary, type HydrationBoundaryProps, type InfiniteQueryState, QueryClientProvider, QueryDevtools, QueryDevtoolsPanel, type QueryDevtoolsPanelProps, type QueryDevtoolsProps, type QueryState, type QueryValue, type UseQueryOptions, bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient };
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { QueryClientProvider
|
|
2
|
-
import {
|
|
3
|
-
import { useIsFetching } from "./use-is-fetching.mjs";
|
|
4
|
-
import { useQuery } from "./use-query.mjs";
|
|
5
|
-
import { useWaterfall } from "./use-waterfall.mjs";
|
|
1
|
+
import { QueryClientProvider } from "./provider.mjs";
|
|
2
|
+
import { QueryDevtools, QueryDevtoolsPanel } from "./devtools.mjs";
|
|
6
3
|
import { HydrationBoundary } from "./hydration-boundary/hydration-boundary-react-server.mjs";
|
|
4
|
+
import { bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient } from "./react-server-hooks.mjs";
|
|
7
5
|
export * from "@raf-query/core";
|
|
8
|
-
export { HydrationBoundary, QueryClientProvider,
|
|
6
|
+
export { HydrationBoundary, QueryClientProvider, QueryDevtools, QueryDevtoolsPanel, bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient };
|
package/dist/index-shared.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useWaterfall } from "./use-waterfall.mjs";
|
|
1
|
+
import { QueryDevtools, QueryDevtoolsPanel, QueryDevtoolsPanelProps, QueryDevtoolsProps } from "./devtools.mjs";
|
|
2
|
+
import { QueryClientProvider } from "./provider.mjs";
|
|
3
|
+
import { QueryState, QueryValue, UseQueryOptions } from "./use-query.mjs";
|
|
4
|
+
import { InfiniteQueryState } from "./use-infinite-query.mjs";
|
|
6
5
|
export * from "@raf-query/core";
|
|
7
|
-
export { QueryClientProvider,
|
|
6
|
+
export { type InfiniteQueryState, QueryClientProvider, QueryDevtools, QueryDevtoolsPanel, type QueryDevtoolsPanelProps, type QueryDevtoolsProps, type QueryState, type QueryValue, type UseQueryOptions };
|
package/dist/index-shared.mjs
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { QueryClientProvider
|
|
2
|
-
import {
|
|
3
|
-
import { useIsFetching } from "./use-is-fetching.mjs";
|
|
4
|
-
import { useQuery } from "./use-query.mjs";
|
|
5
|
-
import { useWaterfall } from "./use-waterfall.mjs";
|
|
1
|
+
import { QueryClientProvider } from "./provider.mjs";
|
|
2
|
+
import { QueryDevtools, QueryDevtoolsPanel } from "./devtools.mjs";
|
|
6
3
|
export * from "@raf-query/core";
|
|
7
|
-
export { QueryClientProvider,
|
|
4
|
+
export { QueryClientProvider, QueryDevtools, QueryDevtoolsPanel };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { QueryDevtools, QueryDevtoolsPanel, QueryDevtoolsPanelProps, QueryDevtoolsProps } from "./devtools.mjs";
|
|
1
2
|
import { QueryClientProvider, useQueryClient } from "./provider.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { UseQueryResult, UseQueryResultWithData, useQuery } from "./use-query.mjs";
|
|
5
|
-
import { useWaterfall } from "./use-waterfall.mjs";
|
|
3
|
+
import { QueryState, QueryValue, UseQueryOptions, useQuery } from "./use-query.mjs";
|
|
4
|
+
import { InfiniteQueryState, useInfiniteQuery } from "./use-infinite-query.mjs";
|
|
6
5
|
import "./index-shared.mjs";
|
|
7
|
-
import { HydrationBoundary } from "./hydration-boundary/hydration-boundary.mjs";
|
|
6
|
+
import { HydrationBoundary, HydrationBoundaryProps } from "./hydration-boundary/hydration-boundary.mjs";
|
|
7
|
+
import { useIsFetching } from "./use-is-fetching.mjs";
|
|
8
|
+
import { bindUseQueryClient } from "./bind.mjs";
|
|
8
9
|
export * from "@raf-query/core";
|
|
9
|
-
export { HydrationBoundary, QueryClientProvider,
|
|
10
|
+
export { HydrationBoundary, type HydrationBoundaryProps, type InfiniteQueryState, QueryClientProvider, QueryDevtools, QueryDevtoolsPanel, type QueryDevtoolsPanelProps, type QueryDevtoolsProps, type QueryState, type QueryValue, type UseQueryOptions, bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { QueryClientProvider, useQueryClient } from "./provider.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { QueryDevtools, QueryDevtoolsPanel } from "./devtools.mjs";
|
|
3
|
+
import { bindUseQueryClient } from "./bind.mjs";
|
|
4
|
+
import { HydrationBoundary } from "./hydration-boundary/hydration-boundary.mjs";
|
|
3
5
|
import { useIsFetching } from "./use-is-fetching.mjs";
|
|
4
6
|
import { useQuery } from "./use-query.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { HydrationBoundary } from "./hydration-boundary/hydration-boundary.mjs";
|
|
7
|
+
import { useInfiniteQuery } from "./use-infinite-query.mjs";
|
|
7
8
|
export * from "@raf-query/core";
|
|
8
|
-
export { HydrationBoundary, QueryClientProvider,
|
|
9
|
+
export { HydrationBoundary, QueryClientProvider, QueryDevtools, QueryDevtoolsPanel, bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient };
|
package/dist/provider.d.mts
CHANGED
|
@@ -2,13 +2,19 @@ import { QueryClient } from "@raf-query/core";
|
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
3
|
//#region src/provider.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Provides a client to the tree, and
|
|
6
|
-
*
|
|
5
|
+
* Provides a client to the tree, and runs its features (focus and
|
|
6
|
+
* reconnect refetching, polling, …) while mounted.
|
|
7
|
+
*
|
|
8
|
+
* @see https://raf-query.katt.dev/docs/ssr-and-hydration#the-provider
|
|
7
9
|
*/
|
|
8
10
|
export declare function QueryClientProvider(props: {
|
|
9
11
|
readonly children?: ReactNode;
|
|
10
|
-
readonly client: QueryClient
|
|
12
|
+
readonly client: QueryClient;
|
|
11
13
|
}): import("react").JSX.Element;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The client from the nearest {@link QueryClientProvider}.
|
|
16
|
+
*
|
|
17
|
+
* @see https://raf-query.katt.dev/docs/api-reference#providers
|
|
18
|
+
*/
|
|
19
|
+
export declare function useQueryClient(): QueryClient;
|
|
14
20
|
//#endregion
|
package/dist/provider.mjs
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { mount } from "@raf-query/core/internal";
|
|
2
3
|
import { createContext, use, useEffect } from "react";
|
|
3
4
|
import { jsx } from "react/jsx-runtime";
|
|
4
5
|
//#region src/provider.tsx
|
|
5
|
-
/**
|
|
6
|
-
* A hook can't know which services the provider's client has, so its verbs
|
|
7
|
-
* take any factory here.
|
|
8
|
-
*/
|
|
9
6
|
const QueryClientContext = createContext(null);
|
|
10
7
|
/**
|
|
11
|
-
* Provides a client to the tree, and
|
|
12
|
-
*
|
|
8
|
+
* Provides a client to the tree, and runs its features (focus and
|
|
9
|
+
* reconnect refetching, polling, …) while mounted.
|
|
10
|
+
*
|
|
11
|
+
* @see https://raf-query.katt.dev/docs/ssr-and-hydration#the-provider
|
|
13
12
|
*/
|
|
14
13
|
function QueryClientProvider(props) {
|
|
15
14
|
const client = props.client;
|
|
16
|
-
useEffect(() =>
|
|
15
|
+
useEffect(() => mount(client), [client]);
|
|
17
16
|
return /* @__PURE__ */ jsx(QueryClientContext, {
|
|
18
17
|
value: client,
|
|
19
18
|
children: props.children
|
|
@@ -23,9 +22,13 @@ function QueryClientProvider(props) {
|
|
|
23
22
|
function useOptionalQueryClient() {
|
|
24
23
|
return use(QueryClientContext);
|
|
25
24
|
}
|
|
26
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* The client from the nearest {@link QueryClientProvider}.
|
|
27
|
+
*
|
|
28
|
+
* @see https://raf-query.katt.dev/docs/api-reference#providers
|
|
29
|
+
*/
|
|
27
30
|
function useQueryClient() {
|
|
28
|
-
const client =
|
|
31
|
+
const client = useOptionalQueryClient();
|
|
29
32
|
if (!client) throw new Error("useQueryClient: no QueryClientProvider above this component");
|
|
30
33
|
return client;
|
|
31
34
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useQueryClient as useQueryClient$1 } from "./provider.mjs";
|
|
2
|
+
import { useQuery as useQuery$1 } from "./use-query.mjs";
|
|
3
|
+
import { useInfiniteQuery as useInfiniteQuery$1 } from "./use-infinite-query.mjs";
|
|
4
|
+
import { useIsFetching as useIsFetching$1 } from "./use-is-fetching.mjs";
|
|
5
|
+
import { QueryClient } from "@raf-query/core";
|
|
6
|
+
import { RootOf } from "@raf-query/core/internal";
|
|
7
|
+
//#region src/react-server-hooks.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* `useQuery` in a server component: throws, since hooks belong in client
|
|
10
|
+
* components.
|
|
11
|
+
*
|
|
12
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
13
|
+
*/
|
|
14
|
+
export declare const useQuery: typeof useQuery$1;
|
|
15
|
+
/**
|
|
16
|
+
* `useInfiniteQuery` in a server component: throws, since hooks belong in client
|
|
17
|
+
* components.
|
|
18
|
+
*
|
|
19
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
20
|
+
*/
|
|
21
|
+
export declare const useInfiniteQuery: typeof useInfiniteQuery$1;
|
|
22
|
+
/**
|
|
23
|
+
* `useIsFetching` in a server component: throws, since hooks belong in client
|
|
24
|
+
* components.
|
|
25
|
+
*
|
|
26
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
27
|
+
*/
|
|
28
|
+
export declare const useIsFetching: typeof useIsFetching$1;
|
|
29
|
+
/**
|
|
30
|
+
* `useQueryClient` in a server component: throws, since hooks belong in client
|
|
31
|
+
* components.
|
|
32
|
+
*
|
|
33
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
34
|
+
*/
|
|
35
|
+
export declare const useQueryClient: typeof useQueryClient$1;
|
|
36
|
+
/**
|
|
37
|
+
* `bindUseQueryClient` runs at module level in a file server modules may
|
|
38
|
+
* import too, so it works here and returns the throwing `useQueryClient`.
|
|
39
|
+
*
|
|
40
|
+
* @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
|
|
41
|
+
*/
|
|
42
|
+
export declare function bindUseQueryClient<T>(): () => QueryClient<RootOf<T>>;
|
|
43
|
+
//#endregion
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/react-server-hooks.ts
|
|
2
|
+
function clientOnly(name) {
|
|
3
|
+
return () => {
|
|
4
|
+
throw new Error(`${name} reads in client components: move this into a file with "use client". Server components start queries with load() and send them with <HydrationBoundary>.`);
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* `useQuery` in a server component: throws, since hooks belong in client
|
|
9
|
+
* components.
|
|
10
|
+
*
|
|
11
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
12
|
+
*/
|
|
13
|
+
const useQuery = /* @__PURE__ */ clientOnly("useQuery");
|
|
14
|
+
/**
|
|
15
|
+
* `useInfiniteQuery` in a server component: throws, since hooks belong in client
|
|
16
|
+
* components.
|
|
17
|
+
*
|
|
18
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
19
|
+
*/
|
|
20
|
+
const useInfiniteQuery = /* @__PURE__ */ clientOnly("useInfiniteQuery");
|
|
21
|
+
/**
|
|
22
|
+
* `useIsFetching` in a server component: throws, since hooks belong in client
|
|
23
|
+
* components.
|
|
24
|
+
*
|
|
25
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
26
|
+
*/
|
|
27
|
+
const useIsFetching = /* @__PURE__ */ clientOnly("useIsFetching");
|
|
28
|
+
/**
|
|
29
|
+
* `useQueryClient` in a server component: throws, since hooks belong in client
|
|
30
|
+
* components.
|
|
31
|
+
*
|
|
32
|
+
* @see https://raf-query.katt.dev/docs/react-server-components
|
|
33
|
+
*/
|
|
34
|
+
const useQueryClient = /* @__PURE__ */ clientOnly("useQueryClient");
|
|
35
|
+
/**
|
|
36
|
+
* `bindUseQueryClient` runs at module level in a file server modules may
|
|
37
|
+
* import too, so it works here and returns the throwing `useQueryClient`.
|
|
38
|
+
*
|
|
39
|
+
* @see https://raf-query.katt.dev/docs/links-and-features#typing-meta-by-its-root
|
|
40
|
+
*/
|
|
41
|
+
function bindUseQueryClient() {
|
|
42
|
+
return useQueryClient;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { bindUseQueryClient, useInfiniteQuery, useIsFetching, useQuery, useQueryClient };
|
|
@@ -5,6 +5,8 @@ import { AnyRouter } from "@tanstack/react-router";
|
|
|
5
5
|
* The browser build of `@raf-query/react/tanstack-router` (the `browser`
|
|
6
6
|
* export condition): the client half only, so the server's dehydration
|
|
7
7
|
* stream stays out of the app bundle.
|
|
8
|
+
*
|
|
9
|
+
* @see https://raf-query.katt.dev/docs/tanstack-start#setup
|
|
8
10
|
*/
|
|
9
11
|
export declare function setupRouterIntegration<TRouter extends AnyRouter>(options: RouterIntegrationOptions<TRouter>): void;
|
|
10
12
|
//#endregion
|
|
@@ -4,6 +4,8 @@ import { handleRedirects, setupClient } from "./tanstack-router-shared.mjs";
|
|
|
4
4
|
* The browser build of `@raf-query/react/tanstack-router` (the `browser`
|
|
5
5
|
* export condition): the client half only, so the server's dehydration
|
|
6
6
|
* stream stays out of the app bundle.
|
|
7
|
+
*
|
|
8
|
+
* @see https://raf-query.katt.dev/docs/tanstack-start#setup
|
|
7
9
|
*/
|
|
8
10
|
function setupRouterIntegration(options) {
|
|
9
11
|
setupClient(options);
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { DehydrateOptions, DehydratedState,
|
|
1
|
+
import { DehydrateOptions, DehydratedState, QueryClient, QueryHandle } from "@raf-query/core";
|
|
2
2
|
import { AnyRouter } from "@tanstack/react-router";
|
|
3
3
|
//#region src/tanstack-router-shared.d.ts
|
|
4
4
|
declare module "@tanstack/react-router" {
|
|
5
5
|
interface SerializableExtensions {
|
|
6
6
|
/**
|
|
7
|
-
* Handles are `{
|
|
8
|
-
* sends as is
|
|
9
|
-
* type
|
|
10
|
-
* `ReadonlyArray<unknown>`, and the handle type names its factory.
|
|
11
|
-
* So `beforeLoad` can put handles in route context.
|
|
7
|
+
* Handles are plain `{ queryKey, input }`, which the router's serializer
|
|
8
|
+
* sends as is. Its type check can't see that on its own: the handle
|
|
9
|
+
* type names its factory. So loaders can return handles.
|
|
12
10
|
*/
|
|
13
11
|
rafQueryHandle: QueryHandle;
|
|
14
12
|
}
|
|
15
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Options for `setupRouterIntegration`.
|
|
16
|
+
*
|
|
17
|
+
* @see https://raf-query.katt.dev/docs/tanstack-start#setup
|
|
18
|
+
*/
|
|
16
19
|
export interface RouterIntegrationOptions<TRouter extends AnyRouter> {
|
|
17
20
|
readonly dehydrateOptions?: DehydrateOptions;
|
|
18
21
|
/** Navigate when a `queryFn` throws `redirect()`. Default `true`. */
|
|
19
22
|
readonly handleRedirects?: boolean;
|
|
20
|
-
readonly hydrateOptions?: HydrateOptions;
|
|
21
23
|
readonly queryClient: QueryClient;
|
|
22
24
|
readonly router: TRouter;
|
|
23
25
|
}
|
|
@@ -1,34 +1,22 @@
|
|
|
1
1
|
import { hydrate } from "@raf-query/core";
|
|
2
|
-
import { Predicate } from "effect";
|
|
3
2
|
import { isRedirect } from "@tanstack/react-router";
|
|
4
3
|
//#region src/tanstack-router-shared.ts
|
|
5
4
|
function hasRafQueries(value) {
|
|
6
|
-
return
|
|
5
|
+
return typeof value === "object" && value !== null && "raf" in value;
|
|
7
6
|
}
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* put Effect's `Stream` and `Queue` in the browser bundle.
|
|
12
|
-
*/
|
|
13
|
-
async function hydrateEach(client, stream, options) {
|
|
14
|
-
const reader = stream.getReader();
|
|
15
|
-
for (;;) {
|
|
16
|
-
const next = await reader.read();
|
|
17
|
-
if (next.done) return;
|
|
18
|
-
hydrate(client, next.value, options);
|
|
19
|
-
}
|
|
7
|
+
/** Hydrate each state as the server's stream delivers it. */
|
|
8
|
+
async function hydrateEach(client, stream) {
|
|
9
|
+
for await (const state of stream) hydrate(client, state);
|
|
20
10
|
}
|
|
21
11
|
function setupClient(options) {
|
|
22
12
|
const router = options.router;
|
|
23
13
|
const client = options.queryClient;
|
|
24
|
-
const hydrateOptions = options.hydrateOptions;
|
|
25
14
|
const originalHydrate = router.options.hydrate;
|
|
26
15
|
router.options.hydrate = async (dehydrated) => {
|
|
27
16
|
await originalHydrate?.(dehydrated);
|
|
28
17
|
if (!hasRafQueries(dehydrated)) return;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
hydrateEach(client, raf.stream, hydrateOptions).catch((error) => {
|
|
18
|
+
hydrate(client, dehydrated.raf.initial);
|
|
19
|
+
hydrateEach(client, dehydrated.raf.stream).catch((error) => {
|
|
32
20
|
console.error("raf-query: reading the query stream failed", error);
|
|
33
21
|
});
|
|
34
22
|
};
|
|
@@ -36,11 +24,13 @@ function setupClient(options) {
|
|
|
36
24
|
function handleRedirects(options) {
|
|
37
25
|
if (!(options.handleRedirects ?? true)) return;
|
|
38
26
|
const router = options.router;
|
|
27
|
+
const handled = /* @__PURE__ */ new WeakSet();
|
|
39
28
|
options.queryClient.subscribe((event) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
const error = event.entry.state.error;
|
|
30
|
+
if (event.type === "updated" && isRedirect(error) && !handled.has(error)) {
|
|
31
|
+
handled.add(error);
|
|
32
|
+
error.options._fromLocation = router.stores.location.get();
|
|
33
|
+
router.navigate(router.resolveRedirect(error).options);
|
|
44
34
|
}
|
|
45
35
|
});
|
|
46
36
|
}
|
|
@@ -5,12 +5,14 @@ import { AnyRouter } from "@tanstack/react-router";
|
|
|
5
5
|
* Connects a query client to a TanStack Router (and TanStack Start) router:
|
|
6
6
|
*
|
|
7
7
|
* - During SSR, sends the cache to the browser with the router's dehydrated
|
|
8
|
-
* state, then streams entries as they start
|
|
9
|
-
*
|
|
8
|
+
* state, then streams entries as they start. Pending entries cross as
|
|
9
|
+
* promises, so the browser resumes them instead of refetching.
|
|
10
10
|
* - Clears the request's cache when the response finishes.
|
|
11
11
|
* - Turns `redirect()` thrown from a `queryFn` into a navigation.
|
|
12
12
|
*
|
|
13
13
|
* Call it in `getRouter`, which runs once per request on the server.
|
|
14
|
+
*
|
|
15
|
+
* @see https://raf-query.katt.dev/docs/tanstack-start#setup
|
|
14
16
|
*/
|
|
15
17
|
export declare function setupRouterIntegration<TRouter extends AnyRouter>(options: RouterIntegrationOptions<TRouter>): void;
|
|
16
18
|
//#endregion
|
package/dist/tanstack-router.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { handleRedirects, setupClient } from "./tanstack-router-shared.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { dehydrateStream, removeAll } from "@raf-query/core";
|
|
3
3
|
//#region src/tanstack-router.ts
|
|
4
4
|
const noop = () => {};
|
|
5
5
|
function setupServer(options) {
|
|
6
6
|
const router = options.router;
|
|
7
|
-
const
|
|
7
|
+
const client = options.queryClient;
|
|
8
8
|
const originalDehydrate = router.options.dehydrate;
|
|
9
9
|
let finish = noop;
|
|
10
10
|
let cleanedUp = false;
|
|
11
11
|
const teardown = () => {
|
|
12
12
|
cleanedUp = true;
|
|
13
13
|
finish();
|
|
14
|
-
|
|
14
|
+
removeAll(client);
|
|
15
15
|
};
|
|
16
16
|
router.serverSsrLifecycle = {
|
|
17
17
|
...router.serverSsrLifecycle,
|
|
@@ -20,21 +20,17 @@ function setupServer(options) {
|
|
|
20
20
|
router.options.dehydrate = async () => {
|
|
21
21
|
const dehydrated = await originalDehydrate?.();
|
|
22
22
|
if (cleanedUp) {
|
|
23
|
-
|
|
23
|
+
removeAll(client);
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
finish = noop;
|
|
30
|
-
Effect.runSync(Scope.close(scope, Exit.void));
|
|
31
|
-
};
|
|
32
|
-
router.serverSsr?.onRenderFinished(() => finish());
|
|
26
|
+
const stream = dehydrateStream(client, options.dehydrateOptions);
|
|
27
|
+
finish = () => stream.close();
|
|
28
|
+
router.serverSsr?.onRenderFinished(() => stream.close());
|
|
33
29
|
return {
|
|
34
30
|
...dehydrated,
|
|
35
31
|
raf: {
|
|
36
32
|
initial: stream.initial,
|
|
37
|
-
stream:
|
|
33
|
+
stream: stream.updates
|
|
38
34
|
}
|
|
39
35
|
};
|
|
40
36
|
};
|
|
@@ -43,12 +39,14 @@ function setupServer(options) {
|
|
|
43
39
|
* Connects a query client to a TanStack Router (and TanStack Start) router:
|
|
44
40
|
*
|
|
45
41
|
* - During SSR, sends the cache to the browser with the router's dehydrated
|
|
46
|
-
* state, then streams entries as they start
|
|
47
|
-
*
|
|
42
|
+
* state, then streams entries as they start. Pending entries cross as
|
|
43
|
+
* promises, so the browser resumes them instead of refetching.
|
|
48
44
|
* - Clears the request's cache when the response finishes.
|
|
49
45
|
* - Turns `redirect()` thrown from a `queryFn` into a navigation.
|
|
50
46
|
*
|
|
51
47
|
* Call it in `getRouter`, which runs once per request on the server.
|
|
48
|
+
*
|
|
49
|
+
* @see https://raf-query.katt.dev/docs/tanstack-start#setup
|
|
52
50
|
*/
|
|
53
51
|
function setupRouterIntegration(options) {
|
|
54
52
|
if (options.router.isServer) setupServer(options);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Thenable } from "@raf-query/core";
|