@effector-tanstack-query/react 0.2.0 → 0.3.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/dist/compat.cjs +47 -0
- package/dist/compat.cjs.map +1 -0
- package/dist/compat.d.cts +53 -0
- package/dist/compat.d.ts +53 -0
- package/dist/compat.js +25 -0
- package/dist/compat.js.map +1 -0
- package/package.json +21 -2
- package/src/compat.tsx +83 -0
package/dist/compat.cjs
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var effectorReact = require('effector-react');
|
|
6
|
+
var reactQuery = require('@tanstack/react-query');
|
|
7
|
+
var core = require('@effector-tanstack-query/core');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
29
|
+
|
|
30
|
+
function QueryClientCompatProvider({
|
|
31
|
+
children,
|
|
32
|
+
defaultOptions
|
|
33
|
+
}) {
|
|
34
|
+
const fromEffector = effectorReact.useUnit(core.$queryClient);
|
|
35
|
+
const [serverFallback] = React__namespace.useState(
|
|
36
|
+
() => reactQuery.isServer ? new reactQuery.QueryClient({ defaultOptions }) : null
|
|
37
|
+
);
|
|
38
|
+
const qc = fromEffector ?? serverFallback;
|
|
39
|
+
if (!qc) {
|
|
40
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
41
|
+
}
|
|
42
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: qc, children });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
exports.QueryClientCompatProvider = QueryClientCompatProvider;
|
|
46
|
+
//# sourceMappingURL=compat.cjs.map
|
|
47
|
+
//# sourceMappingURL=compat.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compat.tsx"],"names":["useUnit","$queryClient","React","isServer","QueryClient","jsx","QueryClientProvider"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DO,SAAS,yBAAA,CAA0B;AAAA,EACxC,QAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,YAAA,GAAeA,sBAAQC,iBAAY,CAAA;AACzC,EAAA,MAAM,CAAC,cAAc,CAAA,GAAUC,gBAAA,CAAA,QAAA;AAAA,IAA6B,MAC1DC,mBAAA,GAAW,IAAIC,uBAAY,EAAE,cAAA,EAAgB,CAAA,GAAI;AAAA,GACnD;AAEA,EAAA,MAAM,KAAK,YAAA,IAAgB,cAAA;AAC3B,EAAA,IAAI,CAAC,EAAA,EAAI;AAMP,IAAA,6DAAU,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAOC,cAAA,CAACC,8BAAA,EAAA,EAAoB,MAAA,EAAQ,EAAA,EAAK,QAAA,EAAS,CAAA;AACpD","file":"compat.cjs","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useUnit } from 'effector-react'\nimport {\n isServer,\n QueryClient,\n QueryClientProvider,\n} from '@tanstack/react-query'\nimport { $queryClient } from '@effector-tanstack-query/core'\n\ntype DefaultOptions = NonNullable<\n ConstructorParameters<typeof QueryClient>[0]\n>['defaultOptions']\n\nexport interface QueryClientCompatProviderProps {\n children: React.ReactNode\n /**\n * `defaultOptions` for the per-render server fallback `QueryClient`\n * (see below). Has no effect on the client — the browser singleton\n * built in your own top-level `<EffectorNext>` setup is what `useQuery`\n * from `@tanstack/react-query` resolves to there. Keep these aligned\n * with your `createQuery({ staleTime, retry, ... })` definitions so\n * server-rendered HTML matches what the client will produce after\n * hydration.\n */\n defaultOptions?: DefaultOptions\n}\n\n/**\n * SSR-safe `QueryClientProvider` bridge for users mixing\n * `@tanstack/react-query` and `@effector-tanstack-query` — the typical\n * \"we're migrating page by page\" case.\n *\n * Why a dedicated component:\n *\n * - **Client**: `useUnit($queryClient)` returns the singleton browser\n * `QueryClient` already mounted by your top-level provider (whichever\n * module calls `setQueryClient(qc)` + `allSettled($queryClient, ...)`\n * for `getClientScope()`). Handing that same instance to\n * `<QueryClientProvider>` means **both APIs share a cache**: prefetch\n * with one, read with the other; `setQueryData` /\n * `invalidateQueries` from one re-renders the other.\n *\n * - **Server (RSC)**: `$queryClient` is `serialize: 'ignore'` (its\n * value is a class instance — not JSON-safe — and per-request\n * QueryClients must NEVER be a module-level singleton on the\n * server). So inside the RSC rendering scope produced by\n * `<EffectorNext values={serialize(scope)}>`, `useUnit($queryClient)`\n * resolves to `null`. We fall back to a throwaway per-render\n * `QueryClient` solely so vanilla `useQuery` has a provider during\n * the server pass. Pair this component with `<HydrationBoundary>`\n * from `@tanstack/react-query` — the boundary will hydrate this\n * fallback client with the prefetched cache, so server-rendered\n * HTML shows data instead of a loading flash. On client hydration\n * the provider re-renders with the singleton browser client and\n * react-query re-subscribes its observers.\n *\n * `useState` makes the fallback per-component-instance (one per render\n * tree), not a module-level singleton — concurrent SSR requests don't\n * share it.\n */\nexport function QueryClientCompatProvider({\n children,\n defaultOptions,\n}: QueryClientCompatProviderProps): React.ReactElement {\n const fromEffector = useUnit($queryClient)\n const [serverFallback] = React.useState<QueryClient | null>(() =>\n isServer ? new QueryClient({ defaultOptions }) : null,\n )\n\n const qc = fromEffector ?? serverFallback\n if (!qc) {\n // Defensive: on the client `fromEffector` is set synchronously by\n // your top-level provider before any render, so this branch is\n // unreachable in practice. If it fires, rendering children without\n // a provider would crash any descendant `useQuery` from\n // `@tanstack/react-query`.\n return <>{children}</>\n }\n\n return <QueryClientProvider client={qc}>{children}</QueryClientProvider>\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
+
|
|
4
|
+
type DefaultOptions = NonNullable<ConstructorParameters<typeof QueryClient>[0]>['defaultOptions'];
|
|
5
|
+
interface QueryClientCompatProviderProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* `defaultOptions` for the per-render server fallback `QueryClient`
|
|
9
|
+
* (see below). Has no effect on the client — the browser singleton
|
|
10
|
+
* built in your own top-level `<EffectorNext>` setup is what `useQuery`
|
|
11
|
+
* from `@tanstack/react-query` resolves to there. Keep these aligned
|
|
12
|
+
* with your `createQuery({ staleTime, retry, ... })` definitions so
|
|
13
|
+
* server-rendered HTML matches what the client will produce after
|
|
14
|
+
* hydration.
|
|
15
|
+
*/
|
|
16
|
+
defaultOptions?: DefaultOptions;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* SSR-safe `QueryClientProvider` bridge for users mixing
|
|
20
|
+
* `@tanstack/react-query` and `@effector-tanstack-query` — the typical
|
|
21
|
+
* "we're migrating page by page" case.
|
|
22
|
+
*
|
|
23
|
+
* Why a dedicated component:
|
|
24
|
+
*
|
|
25
|
+
* - **Client**: `useUnit($queryClient)` returns the singleton browser
|
|
26
|
+
* `QueryClient` already mounted by your top-level provider (whichever
|
|
27
|
+
* module calls `setQueryClient(qc)` + `allSettled($queryClient, ...)`
|
|
28
|
+
* for `getClientScope()`). Handing that same instance to
|
|
29
|
+
* `<QueryClientProvider>` means **both APIs share a cache**: prefetch
|
|
30
|
+
* with one, read with the other; `setQueryData` /
|
|
31
|
+
* `invalidateQueries` from one re-renders the other.
|
|
32
|
+
*
|
|
33
|
+
* - **Server (RSC)**: `$queryClient` is `serialize: 'ignore'` (its
|
|
34
|
+
* value is a class instance — not JSON-safe — and per-request
|
|
35
|
+
* QueryClients must NEVER be a module-level singleton on the
|
|
36
|
+
* server). So inside the RSC rendering scope produced by
|
|
37
|
+
* `<EffectorNext values={serialize(scope)}>`, `useUnit($queryClient)`
|
|
38
|
+
* resolves to `null`. We fall back to a throwaway per-render
|
|
39
|
+
* `QueryClient` solely so vanilla `useQuery` has a provider during
|
|
40
|
+
* the server pass. Pair this component with `<HydrationBoundary>`
|
|
41
|
+
* from `@tanstack/react-query` — the boundary will hydrate this
|
|
42
|
+
* fallback client with the prefetched cache, so server-rendered
|
|
43
|
+
* HTML shows data instead of a loading flash. On client hydration
|
|
44
|
+
* the provider re-renders with the singleton browser client and
|
|
45
|
+
* react-query re-subscribes its observers.
|
|
46
|
+
*
|
|
47
|
+
* `useState` makes the fallback per-component-instance (one per render
|
|
48
|
+
* tree), not a module-level singleton — concurrent SSR requests don't
|
|
49
|
+
* share it.
|
|
50
|
+
*/
|
|
51
|
+
declare function QueryClientCompatProvider({ children, defaultOptions, }: QueryClientCompatProviderProps): React.ReactElement;
|
|
52
|
+
|
|
53
|
+
export { QueryClientCompatProvider, type QueryClientCompatProviderProps };
|
package/dist/compat.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
+
|
|
4
|
+
type DefaultOptions = NonNullable<ConstructorParameters<typeof QueryClient>[0]>['defaultOptions'];
|
|
5
|
+
interface QueryClientCompatProviderProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* `defaultOptions` for the per-render server fallback `QueryClient`
|
|
9
|
+
* (see below). Has no effect on the client — the browser singleton
|
|
10
|
+
* built in your own top-level `<EffectorNext>` setup is what `useQuery`
|
|
11
|
+
* from `@tanstack/react-query` resolves to there. Keep these aligned
|
|
12
|
+
* with your `createQuery({ staleTime, retry, ... })` definitions so
|
|
13
|
+
* server-rendered HTML matches what the client will produce after
|
|
14
|
+
* hydration.
|
|
15
|
+
*/
|
|
16
|
+
defaultOptions?: DefaultOptions;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* SSR-safe `QueryClientProvider` bridge for users mixing
|
|
20
|
+
* `@tanstack/react-query` and `@effector-tanstack-query` — the typical
|
|
21
|
+
* "we're migrating page by page" case.
|
|
22
|
+
*
|
|
23
|
+
* Why a dedicated component:
|
|
24
|
+
*
|
|
25
|
+
* - **Client**: `useUnit($queryClient)` returns the singleton browser
|
|
26
|
+
* `QueryClient` already mounted by your top-level provider (whichever
|
|
27
|
+
* module calls `setQueryClient(qc)` + `allSettled($queryClient, ...)`
|
|
28
|
+
* for `getClientScope()`). Handing that same instance to
|
|
29
|
+
* `<QueryClientProvider>` means **both APIs share a cache**: prefetch
|
|
30
|
+
* with one, read with the other; `setQueryData` /
|
|
31
|
+
* `invalidateQueries` from one re-renders the other.
|
|
32
|
+
*
|
|
33
|
+
* - **Server (RSC)**: `$queryClient` is `serialize: 'ignore'` (its
|
|
34
|
+
* value is a class instance — not JSON-safe — and per-request
|
|
35
|
+
* QueryClients must NEVER be a module-level singleton on the
|
|
36
|
+
* server). So inside the RSC rendering scope produced by
|
|
37
|
+
* `<EffectorNext values={serialize(scope)}>`, `useUnit($queryClient)`
|
|
38
|
+
* resolves to `null`. We fall back to a throwaway per-render
|
|
39
|
+
* `QueryClient` solely so vanilla `useQuery` has a provider during
|
|
40
|
+
* the server pass. Pair this component with `<HydrationBoundary>`
|
|
41
|
+
* from `@tanstack/react-query` — the boundary will hydrate this
|
|
42
|
+
* fallback client with the prefetched cache, so server-rendered
|
|
43
|
+
* HTML shows data instead of a loading flash. On client hydration
|
|
44
|
+
* the provider re-renders with the singleton browser client and
|
|
45
|
+
* react-query re-subscribes its observers.
|
|
46
|
+
*
|
|
47
|
+
* `useState` makes the fallback per-component-instance (one per render
|
|
48
|
+
* tree), not a module-level singleton — concurrent SSR requests don't
|
|
49
|
+
* share it.
|
|
50
|
+
*/
|
|
51
|
+
declare function QueryClientCompatProvider({ children, defaultOptions, }: QueryClientCompatProviderProps): React.ReactElement;
|
|
52
|
+
|
|
53
|
+
export { QueryClientCompatProvider, type QueryClientCompatProviderProps };
|
package/dist/compat.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useUnit } from 'effector-react';
|
|
4
|
+
import { QueryClient, isServer, QueryClientProvider } from '@tanstack/react-query';
|
|
5
|
+
import { $queryClient } from '@effector-tanstack-query/core';
|
|
6
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function QueryClientCompatProvider({
|
|
9
|
+
children,
|
|
10
|
+
defaultOptions
|
|
11
|
+
}) {
|
|
12
|
+
const fromEffector = useUnit($queryClient);
|
|
13
|
+
const [serverFallback] = React.useState(
|
|
14
|
+
() => isServer ? new QueryClient({ defaultOptions }) : null
|
|
15
|
+
);
|
|
16
|
+
const qc = fromEffector ?? serverFallback;
|
|
17
|
+
if (!qc) {
|
|
18
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
19
|
+
}
|
|
20
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: qc, children });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { QueryClientCompatProvider };
|
|
24
|
+
//# sourceMappingURL=compat.js.map
|
|
25
|
+
//# sourceMappingURL=compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compat.tsx"],"names":[],"mappings":";;;;;;AA8DO,SAAS,yBAAA,CAA0B;AAAA,EACxC,QAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,YAAA,GAAe,QAAQ,YAAY,CAAA;AACzC,EAAA,MAAM,CAAC,cAAc,CAAA,GAAU,KAAA,CAAA,QAAA;AAAA,IAA6B,MAC1D,QAAA,GAAW,IAAI,YAAY,EAAE,cAAA,EAAgB,CAAA,GAAI;AAAA,GACnD;AAEA,EAAA,MAAM,KAAK,YAAA,IAAgB,cAAA;AAC3B,EAAA,IAAI,CAAC,EAAA,EAAI;AAMP,IAAA,uCAAU,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAO,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAQ,EAAA,EAAK,QAAA,EAAS,CAAA;AACpD","file":"compat.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useUnit } from 'effector-react'\nimport {\n isServer,\n QueryClient,\n QueryClientProvider,\n} from '@tanstack/react-query'\nimport { $queryClient } from '@effector-tanstack-query/core'\n\ntype DefaultOptions = NonNullable<\n ConstructorParameters<typeof QueryClient>[0]\n>['defaultOptions']\n\nexport interface QueryClientCompatProviderProps {\n children: React.ReactNode\n /**\n * `defaultOptions` for the per-render server fallback `QueryClient`\n * (see below). Has no effect on the client — the browser singleton\n * built in your own top-level `<EffectorNext>` setup is what `useQuery`\n * from `@tanstack/react-query` resolves to there. Keep these aligned\n * with your `createQuery({ staleTime, retry, ... })` definitions so\n * server-rendered HTML matches what the client will produce after\n * hydration.\n */\n defaultOptions?: DefaultOptions\n}\n\n/**\n * SSR-safe `QueryClientProvider` bridge for users mixing\n * `@tanstack/react-query` and `@effector-tanstack-query` — the typical\n * \"we're migrating page by page\" case.\n *\n * Why a dedicated component:\n *\n * - **Client**: `useUnit($queryClient)` returns the singleton browser\n * `QueryClient` already mounted by your top-level provider (whichever\n * module calls `setQueryClient(qc)` + `allSettled($queryClient, ...)`\n * for `getClientScope()`). Handing that same instance to\n * `<QueryClientProvider>` means **both APIs share a cache**: prefetch\n * with one, read with the other; `setQueryData` /\n * `invalidateQueries` from one re-renders the other.\n *\n * - **Server (RSC)**: `$queryClient` is `serialize: 'ignore'` (its\n * value is a class instance — not JSON-safe — and per-request\n * QueryClients must NEVER be a module-level singleton on the\n * server). So inside the RSC rendering scope produced by\n * `<EffectorNext values={serialize(scope)}>`, `useUnit($queryClient)`\n * resolves to `null`. We fall back to a throwaway per-render\n * `QueryClient` solely so vanilla `useQuery` has a provider during\n * the server pass. Pair this component with `<HydrationBoundary>`\n * from `@tanstack/react-query` — the boundary will hydrate this\n * fallback client with the prefetched cache, so server-rendered\n * HTML shows data instead of a loading flash. On client hydration\n * the provider re-renders with the singleton browser client and\n * react-query re-subscribes its observers.\n *\n * `useState` makes the fallback per-component-instance (one per render\n * tree), not a module-level singleton — concurrent SSR requests don't\n * share it.\n */\nexport function QueryClientCompatProvider({\n children,\n defaultOptions,\n}: QueryClientCompatProviderProps): React.ReactElement {\n const fromEffector = useUnit($queryClient)\n const [serverFallback] = React.useState<QueryClient | null>(() =>\n isServer ? new QueryClient({ defaultOptions }) : null,\n )\n\n const qc = fromEffector ?? serverFallback\n if (!qc) {\n // Defensive: on the client `fromEffector` is set synchronously by\n // your top-level provider before any render, so this branch is\n // unreachable in practice. If it fires, rendering children without\n // a provider would crash any descendant `useQuery` from\n // `@tanstack/react-query`.\n return <>{children}</>\n }\n\n return <QueryClientProvider client={qc}>{children}</QueryClientProvider>\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effector-tanstack-query/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React hooks for @effector-tanstack-query/core — useQuery, useMutation, useInfiniteQuery, useSuspenseQuery, useSuspenseInfiniteQuery",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ilya Agarkov <ilya.al.ag@gmail.com>",
|
|
@@ -36,6 +36,16 @@
|
|
|
36
36
|
"default": "./dist/index.cjs"
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
|
+
"./compat": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/compat.d.ts",
|
|
42
|
+
"default": "./dist/compat.js"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/compat.d.cts",
|
|
46
|
+
"default": "./dist/compat.cjs"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
39
49
|
"./package.json": "./package.json"
|
|
40
50
|
},
|
|
41
51
|
"files": [
|
|
@@ -45,14 +55,23 @@
|
|
|
45
55
|
],
|
|
46
56
|
"sideEffects": false,
|
|
47
57
|
"dependencies": {
|
|
48
|
-
"@effector-tanstack-query/core": "0.
|
|
58
|
+
"@effector-tanstack-query/core": "0.3.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@tanstack/react-query": "^5.0.0"
|
|
49
62
|
},
|
|
50
63
|
"peerDependencies": {
|
|
51
64
|
"@tanstack/query-core": "^5.0.0",
|
|
65
|
+
"@tanstack/react-query": "^5.0.0",
|
|
52
66
|
"effector": ">=23.0.0",
|
|
53
67
|
"effector-react": ">=23.0.0",
|
|
54
68
|
"react": "^18.0.0 || ^19.0.0"
|
|
55
69
|
},
|
|
70
|
+
"peerDependenciesMeta": {
|
|
71
|
+
"@tanstack/react-query": {
|
|
72
|
+
"optional": true
|
|
73
|
+
}
|
|
74
|
+
},
|
|
56
75
|
"scripts": {
|
|
57
76
|
"build": "tsup && node ./scripts/inject-use-client.mjs",
|
|
58
77
|
"build:watch": "tsup --watch",
|
package/src/compat.tsx
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { useUnit } from 'effector-react'
|
|
5
|
+
import {
|
|
6
|
+
isServer,
|
|
7
|
+
QueryClient,
|
|
8
|
+
QueryClientProvider,
|
|
9
|
+
} from '@tanstack/react-query'
|
|
10
|
+
import { $queryClient } from '@effector-tanstack-query/core'
|
|
11
|
+
|
|
12
|
+
type DefaultOptions = NonNullable<
|
|
13
|
+
ConstructorParameters<typeof QueryClient>[0]
|
|
14
|
+
>['defaultOptions']
|
|
15
|
+
|
|
16
|
+
export interface QueryClientCompatProviderProps {
|
|
17
|
+
children: React.ReactNode
|
|
18
|
+
/**
|
|
19
|
+
* `defaultOptions` for the per-render server fallback `QueryClient`
|
|
20
|
+
* (see below). Has no effect on the client — the browser singleton
|
|
21
|
+
* built in your own top-level `<EffectorNext>` setup is what `useQuery`
|
|
22
|
+
* from `@tanstack/react-query` resolves to there. Keep these aligned
|
|
23
|
+
* with your `createQuery({ staleTime, retry, ... })` definitions so
|
|
24
|
+
* server-rendered HTML matches what the client will produce after
|
|
25
|
+
* hydration.
|
|
26
|
+
*/
|
|
27
|
+
defaultOptions?: DefaultOptions
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* SSR-safe `QueryClientProvider` bridge for users mixing
|
|
32
|
+
* `@tanstack/react-query` and `@effector-tanstack-query` — the typical
|
|
33
|
+
* "we're migrating page by page" case.
|
|
34
|
+
*
|
|
35
|
+
* Why a dedicated component:
|
|
36
|
+
*
|
|
37
|
+
* - **Client**: `useUnit($queryClient)` returns the singleton browser
|
|
38
|
+
* `QueryClient` already mounted by your top-level provider (whichever
|
|
39
|
+
* module calls `setQueryClient(qc)` + `allSettled($queryClient, ...)`
|
|
40
|
+
* for `getClientScope()`). Handing that same instance to
|
|
41
|
+
* `<QueryClientProvider>` means **both APIs share a cache**: prefetch
|
|
42
|
+
* with one, read with the other; `setQueryData` /
|
|
43
|
+
* `invalidateQueries` from one re-renders the other.
|
|
44
|
+
*
|
|
45
|
+
* - **Server (RSC)**: `$queryClient` is `serialize: 'ignore'` (its
|
|
46
|
+
* value is a class instance — not JSON-safe — and per-request
|
|
47
|
+
* QueryClients must NEVER be a module-level singleton on the
|
|
48
|
+
* server). So inside the RSC rendering scope produced by
|
|
49
|
+
* `<EffectorNext values={serialize(scope)}>`, `useUnit($queryClient)`
|
|
50
|
+
* resolves to `null`. We fall back to a throwaway per-render
|
|
51
|
+
* `QueryClient` solely so vanilla `useQuery` has a provider during
|
|
52
|
+
* the server pass. Pair this component with `<HydrationBoundary>`
|
|
53
|
+
* from `@tanstack/react-query` — the boundary will hydrate this
|
|
54
|
+
* fallback client with the prefetched cache, so server-rendered
|
|
55
|
+
* HTML shows data instead of a loading flash. On client hydration
|
|
56
|
+
* the provider re-renders with the singleton browser client and
|
|
57
|
+
* react-query re-subscribes its observers.
|
|
58
|
+
*
|
|
59
|
+
* `useState` makes the fallback per-component-instance (one per render
|
|
60
|
+
* tree), not a module-level singleton — concurrent SSR requests don't
|
|
61
|
+
* share it.
|
|
62
|
+
*/
|
|
63
|
+
export function QueryClientCompatProvider({
|
|
64
|
+
children,
|
|
65
|
+
defaultOptions,
|
|
66
|
+
}: QueryClientCompatProviderProps): React.ReactElement {
|
|
67
|
+
const fromEffector = useUnit($queryClient)
|
|
68
|
+
const [serverFallback] = React.useState<QueryClient | null>(() =>
|
|
69
|
+
isServer ? new QueryClient({ defaultOptions }) : null,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
const qc = fromEffector ?? serverFallback
|
|
73
|
+
if (!qc) {
|
|
74
|
+
// Defensive: on the client `fromEffector` is set synchronously by
|
|
75
|
+
// your top-level provider before any render, so this branch is
|
|
76
|
+
// unreachable in practice. If it fires, rendering children without
|
|
77
|
+
// a provider would crash any descendant `useQuery` from
|
|
78
|
+
// `@tanstack/react-query`.
|
|
79
|
+
return <>{children}</>
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return <QueryClientProvider client={qc}>{children}</QueryClientProvider>
|
|
83
|
+
}
|