@uniai-fe/next-providers 0.1.16 → 0.1.17
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/package.json +9 -9
- package/src/NextRoots.tsx +47 -17
- package/src/provider/JotaiProvider.tsx +41 -5
- package/src/provider/ReactQueryProvider.tsx +121 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/next-providers",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"description": "Next.js State Providers for UNIAI FE Projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
|
-
"packageManager": "pnpm@10.
|
|
13
|
+
"packageManager": "pnpm@10.33.3",
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=24",
|
|
16
16
|
"pnpm": ">=10"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"next": ">= 15",
|
|
47
47
|
"react": ">= 19",
|
|
48
48
|
"react-dom": ">= 19",
|
|
49
|
-
"@tanstack/react-query": ">= 5",
|
|
49
|
+
"@tanstack/react-query": ">= 5.100.9",
|
|
50
50
|
"jotai": ">= 2",
|
|
51
51
|
"styled-components": ">= 6",
|
|
52
52
|
"airtable": ">= 0.12",
|
|
@@ -72,19 +72,19 @@
|
|
|
72
72
|
"@uniai-fe/runtime-env": "workspace:*",
|
|
73
73
|
"@uniai-fe/util-jotai": "workspace:*",
|
|
74
74
|
"@uniai-fe/i18n": "workspace:*",
|
|
75
|
-
"@tanstack/react-query": "^5.
|
|
75
|
+
"@tanstack/react-query": "^5.100.9",
|
|
76
76
|
"@types/node": "^24.10.2",
|
|
77
77
|
"@types/react": "^19.2.14",
|
|
78
78
|
"@types/react-dom": "^19.2.3",
|
|
79
79
|
"airtable": "^0.12.2",
|
|
80
80
|
"eslint": "^9.39.2",
|
|
81
|
-
"jotai": "^2.
|
|
81
|
+
"jotai": "^2.20.0",
|
|
82
82
|
"jotai-tanstack-query": "^0.11.0",
|
|
83
83
|
"next": "^15.5.11",
|
|
84
|
-
"prettier": "^3.8.
|
|
85
|
-
"react": "^19.2.
|
|
86
|
-
"react-dom": "^19.2.
|
|
84
|
+
"prettier": "^3.8.3",
|
|
85
|
+
"react": "^19.2.5",
|
|
86
|
+
"react-dom": "^19.2.5",
|
|
87
87
|
"styled-components": "6.1.19",
|
|
88
|
-
"typescript": "
|
|
88
|
+
"typescript": "5.9.3"
|
|
89
89
|
}
|
|
90
90
|
}
|
package/src/NextRoots.tsx
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
import StyledComponentsRegistry from "./lib/StyledComponentsRegistry";
|
|
2
2
|
import AirtableProvider from "./provider/AirtableProvider";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
JotaiProvider,
|
|
5
|
+
type JotaiProviderProps,
|
|
6
|
+
} from "./provider/JotaiProvider";
|
|
7
|
+
import {
|
|
8
|
+
ReactQueryProvider,
|
|
9
|
+
type ReactQueryProviderProps,
|
|
10
|
+
} from "./provider/ReactQueryProvider";
|
|
5
11
|
import SetQueryCookie from "./lib/SetQueryCookie";
|
|
6
12
|
import SystemThemeChecker from "./lib/SystemThemeChecker";
|
|
7
13
|
import type { SystemLanguageType } from "@uniai-fe/next-devkit/types";
|
|
8
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Next.js Root Layout Provider 구성 props
|
|
17
|
+
* @typedef {object} NextRootsProps
|
|
18
|
+
* @property {SystemLanguageType} [locale] AirtableProvider에 전달할 시스템 언어
|
|
19
|
+
* @property {{ exceptPaths: string[] }} [systemThemeOptions] 시스템 테마 체크 옵션
|
|
20
|
+
* @property {React.ReactNode} [modalProviders] 서비스별 modal provider 슬롯
|
|
21
|
+
* @property {Omit<ReactQueryProviderProps, "children">} [reactQueryProviderProps] ReactQueryProvider로 전달할 설정
|
|
22
|
+
* @property {Omit<JotaiProviderProps, "children">} [jotaiProviderProps] JotaiProvider로 전달할 설정
|
|
23
|
+
* @property {React.ReactNode} children Root Provider 하위에 배치할 앱 트리
|
|
24
|
+
*/
|
|
25
|
+
type NextRootsProps = {
|
|
26
|
+
locale?: SystemLanguageType;
|
|
27
|
+
systemThemeOptions?: { exceptPaths: string[] };
|
|
28
|
+
modalProviders?: React.ReactNode;
|
|
29
|
+
reactQueryProviderProps?: Omit<ReactQueryProviderProps, "children">;
|
|
30
|
+
jotaiProviderProps?: Omit<JotaiProviderProps, "children">;
|
|
31
|
+
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
};
|
|
34
|
+
|
|
9
35
|
/**
|
|
10
36
|
* Next.js Root Layout에 적용할 Provider 및 유틸리티 도구 집합
|
|
11
37
|
* @component
|
|
@@ -13,38 +39,42 @@ import type { SystemLanguageType } from "@uniai-fe/next-devkit/types";
|
|
|
13
39
|
* @param {SystemLanguageType} [props.locale] 언어설정; "ko", "en"
|
|
14
40
|
* @param {object} [props.systemThemeOptions] 시스템 테마 체크 옵션
|
|
15
41
|
* @param {string[]} [props.systemThemeOptions.exceptPaths] 테마 체크 제외 경로
|
|
16
|
-
* @param {
|
|
42
|
+
* @param {object} [props.reactQueryProviderProps] React Query Provider 전달 props
|
|
43
|
+
* @param {object} [props.jotaiProviderProps] Jotai Provider 전달 props
|
|
44
|
+
* @param {React.ReactNode} [props.modalProviders] 모달 Provider 슬롯(서비스별 modal provider 선택)
|
|
17
45
|
* @param {() => void} [props.onRouteChange] 경로 변경 시 실행할 콜백(예: 모달 스택 초기화)
|
|
18
46
|
* @param {React.ReactNode} props.children
|
|
47
|
+
* @returns {React.JSX.Element}
|
|
19
48
|
* @desc
|
|
20
|
-
* - React Query
|
|
21
|
-
* - Jotai
|
|
22
|
-
* -
|
|
23
|
-
* -
|
|
24
|
-
* - Router Event Detector
|
|
49
|
+
* - React Query Provider를 최상위에 두어 하위 Jotai hydration에서 동일 QueryClient를 읽을 수 있게 한다.
|
|
50
|
+
* - Jotai Provider는 react-query 연동 atom과 서비스별 store를 함께 제공한다.
|
|
51
|
+
* - StyledComponentsRegistry 내부에서 AirtableProvider와 SystemThemeChecker를 렌더링한다.
|
|
52
|
+
* - modalProviders는 서비스별 modal stack/provider 조합을 children 옆 슬롯으로 합성한다.
|
|
25
53
|
*/
|
|
26
54
|
export default function NextRoots({
|
|
27
55
|
locale = "ko",
|
|
28
56
|
systemThemeOptions,
|
|
29
57
|
modalProviders,
|
|
58
|
+
reactQueryProviderProps,
|
|
59
|
+
jotaiProviderProps,
|
|
30
60
|
|
|
31
61
|
children,
|
|
32
|
-
}: {
|
|
33
|
-
locale?: SystemLanguageType;
|
|
34
|
-
systemThemeOptions?: { exceptPaths: string[] };
|
|
35
|
-
modalProviders?: React.ReactNode;
|
|
36
|
-
|
|
37
|
-
children: React.ReactNode;
|
|
38
|
-
}) {
|
|
62
|
+
}: NextRootsProps) {
|
|
39
63
|
return (
|
|
40
|
-
|
|
41
|
-
|
|
64
|
+
// React Query client는 JotaiHydrateAtoms에서도 같은 인스턴스를 참조해야 하므로 가장 바깥에 둔다.
|
|
65
|
+
<ReactQueryProvider {...reactQueryProviderProps}>
|
|
66
|
+
{/* Jotai store 설정은 React Query context 하위에서 적용한다. */}
|
|
67
|
+
<JotaiProvider {...jotaiProviderProps}>
|
|
42
68
|
<SetQueryCookie />
|
|
69
|
+
{/* styled-components SSR registry는 실제 화면 트리를 감싸서 style collection 범위를 만든다. */}
|
|
43
70
|
<StyledComponentsRegistry>
|
|
71
|
+
{/* locale은 Airtable 기반 다국어/환경 데이터 provider에만 전달한다. */}
|
|
44
72
|
<AirtableProvider locale={locale}>
|
|
45
73
|
{children}
|
|
74
|
+
{/* 서비스별 modal provider는 앱 children과 같은 provider scope에 둔다. */}
|
|
46
75
|
{modalProviders}
|
|
47
76
|
</AirtableProvider>
|
|
77
|
+
{/* theme check는 provider scope 안에서 route/path 예외 설정을 읽어 실행한다. */}
|
|
48
78
|
<SystemThemeChecker exceptPaths={systemThemeOptions?.exceptPaths} />
|
|
49
79
|
</StyledComponentsRegistry>
|
|
50
80
|
</JotaiProvider>
|
|
@@ -1,22 +1,58 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
4
|
import { Provider } from "jotai";
|
|
4
5
|
import { useHydrateAtoms } from "jotai/react/utils";
|
|
5
6
|
import { queryClientAtom } from "jotai-tanstack-query";
|
|
6
|
-
import {
|
|
7
|
+
import type { ComponentProps } from "react";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Jotai Provider 전달 props
|
|
11
|
+
* @typedef {ComponentProps<typeof Provider>} JotaiProviderProps
|
|
12
|
+
* @property {React.ReactNode} [children] Jotai store 범위 안에서 렌더링할 하위 요소
|
|
13
|
+
* @property {ReturnType<import("jotai").createStore>} [store] 서비스 또는 테스트에서 주입할 Jotai store 인스턴스
|
|
14
|
+
*/
|
|
15
|
+
export type JotaiProviderProps = ComponentProps<typeof Provider>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Jotai atom에 React Query client를 연결하는 Hydration 컴포넌트
|
|
19
|
+
* @component
|
|
20
|
+
* @param {Pick<JotaiProviderProps, "children">} props
|
|
21
|
+
* @param {React.ReactNode} [props.children] hydrate 이후 렌더링할 하위 요소
|
|
22
|
+
* @desc
|
|
23
|
+
* - ReactQueryProvider 하위에서만 사용한다.
|
|
24
|
+
* - queryClientAtom에는 React Query Context의 QueryClient와 동일한 인스턴스를 주입한다.
|
|
25
|
+
* - getQueryClient를 직접 재호출하지 않아 SSR/CSR 간 QueryClient 불일치를 방지한다.
|
|
26
|
+
*/
|
|
27
|
+
export function JotaiHydrateAtoms({
|
|
28
|
+
children,
|
|
29
|
+
}: Pick<JotaiProviderProps, "children">) {
|
|
30
|
+
// React Query Provider가 context에 올린 QueryClient 인스턴스를 그대로 읽는다.
|
|
31
|
+
const queryClient = useQueryClient();
|
|
32
|
+
|
|
33
|
+
// jotai-tanstack-query atom이 React Query Provider와 동일한 client를 보도록 hydrate한다.
|
|
34
|
+
useHydrateAtoms([[queryClientAtom, queryClient]]);
|
|
35
|
+
|
|
36
|
+
// Hydration 전용 래퍼이므로 별도 DOM 없이 children만 반환한다.
|
|
10
37
|
return children;
|
|
11
38
|
}
|
|
12
39
|
|
|
13
40
|
/**
|
|
14
41
|
* Jotai 상태 공급자
|
|
15
42
|
* @component
|
|
43
|
+
* @param {JotaiProviderProps} props
|
|
44
|
+
* @param {React.ReactNode} [props.children] Jotai Provider 하위에 배치할 앱 트리
|
|
45
|
+
* @param {JotaiProviderProps["store"]} [props.store] 외부에서 생성한 Jotai store 인스턴스
|
|
46
|
+
* @desc
|
|
47
|
+
* - store가 전달되면 해당 store를 Provider에 그대로 주입한다.
|
|
48
|
+
* - store가 없으면 Jotai Provider의 기본 store 생성 정책을 따른다.
|
|
49
|
+
* - 하위 Hydration 컴포넌트에서 queryClientAtom을 React Query Context와 동기화한다.
|
|
16
50
|
*/
|
|
17
|
-
export function JotaiProvider({ children }:
|
|
51
|
+
export function JotaiProvider({ children, store }: JotaiProviderProps) {
|
|
18
52
|
return (
|
|
19
|
-
|
|
53
|
+
// 서비스별 store 주입을 허용하되 기본 사용자는 별도 설정 없이 사용할 수 있게 둔다.
|
|
54
|
+
<Provider store={store}>
|
|
55
|
+
{/* React Query client atom hydration은 Jotai store 범위 안에서 실행되어야 한다. */}
|
|
20
56
|
<JotaiHydrateAtoms>{children}</JotaiHydrateAtoms>
|
|
21
57
|
</Provider>
|
|
22
58
|
);
|
|
@@ -2,10 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
defaultShouldDehydrateQuery,
|
|
5
|
-
|
|
5
|
+
environmentManager,
|
|
6
6
|
QueryClient,
|
|
7
7
|
QueryClientProvider,
|
|
8
8
|
} from "@tanstack/react-query";
|
|
9
|
+
import type { QueryClientConfig } from "@tanstack/react-query";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* React Query Provider 전달 props
|
|
13
|
+
* @typedef {object} ReactQueryProviderProps
|
|
14
|
+
* @property {React.ReactNode} children React Query Provider 하위에 배치할 앱 트리
|
|
15
|
+
* @property {QueryClient} [queryClient] 외부에서 직접 생성해 주입할 QueryClient 인스턴스
|
|
16
|
+
* @property {QueryClientConfig} [queryClientConfig] 내부 QueryClient 생성 시 병합할 설정
|
|
17
|
+
*/
|
|
18
|
+
export type ReactQueryProviderProps = {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
queryClient?: QueryClient;
|
|
21
|
+
queryClientConfig?: QueryClientConfig;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* QueryClient 기본 옵션 타입
|
|
26
|
+
* @typedef {NonNullable<QueryClientConfig["defaultOptions"]>} QueryClientDefaultOptions
|
|
27
|
+
* @desc QueryClientConfig.defaultOptions는 optional이므로 내부 병합 로직에서는 NonNullable 타입으로 고정한다.
|
|
28
|
+
*/
|
|
29
|
+
type QueryClientDefaultOptions = NonNullable<
|
|
30
|
+
QueryClientConfig["defaultOptions"]
|
|
31
|
+
>;
|
|
9
32
|
|
|
10
33
|
/**
|
|
11
34
|
* 클라이언트 단에서의 React Query client
|
|
@@ -14,47 +37,105 @@ import {
|
|
|
14
37
|
let browserQueryClient: QueryClient | undefined = undefined;
|
|
15
38
|
|
|
16
39
|
/**
|
|
17
|
-
* React Query
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
40
|
+
* next-providers가 기본으로 제공하는 React Query 전역 옵션
|
|
41
|
+
* @type {QueryClientDefaultOptions}
|
|
42
|
+
* @desc
|
|
43
|
+
* - 서비스별 queryClientConfig가 전달되면 같은 depth의 옵션을 덮어쓴다.
|
|
44
|
+
* - shouldDehydrateQuery는 pending query dehydration 정책을 기본값 위에 추가한다.
|
|
20
45
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
46
|
+
const defaultQueryClientOptions: QueryClientDefaultOptions = {
|
|
47
|
+
queries: {
|
|
48
|
+
// onError: queryErrorHandler,
|
|
49
|
+
staleTime: 600000,
|
|
50
|
+
gcTime: 900000, // 기존 cacheTime에서 명칭 변경, 원래 "가비지 콜렉션 시간"을 의미하였음.
|
|
51
|
+
refetchOnMount: false,
|
|
52
|
+
refetchOnReconnect: false,
|
|
53
|
+
refetchOnWindowFocus: false,
|
|
54
|
+
retry: false,
|
|
55
|
+
},
|
|
56
|
+
dehydrate: {
|
|
57
|
+
// include pending queries in dehydration
|
|
58
|
+
shouldDehydrateQuery: query =>
|
|
59
|
+
defaultShouldDehydrateQuery(query) || query.state.status === "pending",
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 기본 QueryClient 옵션과 서비스별 옵션을 병합한다.
|
|
65
|
+
* @param {QueryClientConfig} [queryClientConfig] 서비스에서 전달한 QueryClient 생성 설정
|
|
66
|
+
* @returns {QueryClientConfig}
|
|
67
|
+
* @desc
|
|
68
|
+
* - 최상위 QueryClientConfig는 서비스 설정을 우선한다.
|
|
69
|
+
* - defaultOptions 하위의 queries/mutations/hydrate/dehydrate는 depth별로 병합한다.
|
|
70
|
+
* - 서비스가 dehydrate.shouldDehydrateQuery를 넘기면 기본 pending dehydration 정책을 대체한다.
|
|
71
|
+
*/
|
|
72
|
+
function resolveQueryClientConfig(
|
|
73
|
+
queryClientConfig?: QueryClientConfig,
|
|
74
|
+
): QueryClientConfig {
|
|
75
|
+
return {
|
|
76
|
+
// queryCache, mutationCache, logger 등 최상위 설정은 서비스 설정을 그대로 보존한다.
|
|
77
|
+
...queryClientConfig,
|
|
24
78
|
defaultOptions: {
|
|
79
|
+
// next-providers 기본값을 먼저 놓고, 서비스 defaultOptions로 덮어쓸 수 있게 한다.
|
|
80
|
+
...defaultQueryClientOptions,
|
|
81
|
+
...queryClientConfig?.defaultOptions,
|
|
25
82
|
queries: {
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
83
|
+
// query 기본 정책은 유지하되 서비스별 query option이 있으면 우선한다.
|
|
84
|
+
...defaultQueryClientOptions.queries,
|
|
85
|
+
...queryClientConfig?.defaultOptions?.queries,
|
|
86
|
+
},
|
|
87
|
+
mutations: {
|
|
88
|
+
// mutation 기본 옵션도 future-proofing을 위해 같은 병합 규칙을 적용한다.
|
|
89
|
+
...defaultQueryClientOptions.mutations,
|
|
90
|
+
...queryClientConfig?.defaultOptions?.mutations,
|
|
91
|
+
},
|
|
92
|
+
hydrate: {
|
|
93
|
+
// hydrate 옵션은 React Query SSR hydration 정책 확장을 위해 분리 병합한다.
|
|
94
|
+
...defaultQueryClientOptions.hydrate,
|
|
95
|
+
...queryClientConfig?.defaultOptions?.hydrate,
|
|
33
96
|
},
|
|
34
97
|
dehydrate: {
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
query.state.status === "pending",
|
|
98
|
+
// dehydrate 옵션은 pending query 포함 정책을 기본값으로 제공한다.
|
|
99
|
+
...defaultQueryClientOptions.dehydrate,
|
|
100
|
+
...queryClientConfig?.defaultOptions?.dehydrate,
|
|
39
101
|
},
|
|
40
102
|
},
|
|
41
|
-
}
|
|
103
|
+
};
|
|
42
104
|
}
|
|
43
105
|
|
|
44
106
|
/**
|
|
45
107
|
* React Query client 생성
|
|
108
|
+
* - 서비스 전역에 적용할 쿼리옵션을 사전에 지정하여 생성
|
|
109
|
+
* @param {QueryClientConfig} [queryClientConfig] 기본 옵션과 병합할 QueryClient 생성 설정
|
|
46
110
|
* @return {QueryClient}
|
|
47
111
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
112
|
+
function makeQueryClient(queryClientConfig?: QueryClientConfig): QueryClient {
|
|
113
|
+
// QueryClient 생성 전 next-providers 기본값과 서비스 override를 한 번만 병합한다.
|
|
114
|
+
return new QueryClient(resolveQueryClientConfig(queryClientConfig));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* React Query client 생성
|
|
119
|
+
* @param {QueryClientConfig} [queryClientConfig] 내부 QueryClient 생성 시 사용할 설정
|
|
120
|
+
* @return {QueryClient}
|
|
121
|
+
* @desc
|
|
122
|
+
* - 서버에서는 요청 간 캐시 공유를 피하기 위해 항상 새 QueryClient를 생성한다.
|
|
123
|
+
* - 브라우저에서는 최초 생성한 QueryClient를 재사용해 초기 suspense 중 client 재생성을 막는다.
|
|
124
|
+
* - 브라우저 singleton이 이미 생성된 뒤 들어온 queryClientConfig는 반영되지 않는다.
|
|
125
|
+
*/
|
|
126
|
+
export function getQueryClient(
|
|
127
|
+
queryClientConfig?: QueryClientConfig,
|
|
128
|
+
): QueryClient {
|
|
129
|
+
if (environmentManager.isServer()) {
|
|
50
130
|
// Server: always make a new query client
|
|
51
|
-
return makeQueryClient();
|
|
131
|
+
return makeQueryClient(queryClientConfig);
|
|
52
132
|
} else {
|
|
53
133
|
// Browser: make a new query client if we don't already have one
|
|
54
134
|
// This is very important, so we don't re-make a new client if React
|
|
55
135
|
// suspends during the initial render. This may not be needed if we
|
|
56
136
|
// have a suspense boundary BELOW the creation of the query client
|
|
57
|
-
if (!browserQueryClient)
|
|
137
|
+
if (!browserQueryClient)
|
|
138
|
+
browserQueryClient = makeQueryClient(queryClientConfig);
|
|
58
139
|
return browserQueryClient;
|
|
59
140
|
}
|
|
60
141
|
}
|
|
@@ -62,21 +143,33 @@ export function getQueryClient(): QueryClient {
|
|
|
62
143
|
/**
|
|
63
144
|
* ReactQuery 상태 공급자
|
|
64
145
|
* @component
|
|
146
|
+
* @param {ReactQueryProviderProps} props
|
|
147
|
+
* @param {React.ReactNode} props.children React Query Provider 하위에 배치할 앱 트리
|
|
148
|
+
* @param {QueryClient} [props.queryClient] 외부에서 직접 생성해 주입할 QueryClient 인스턴스
|
|
149
|
+
* @param {QueryClientConfig} [props.queryClientConfig] 내부 QueryClient 생성 시 병합할 설정
|
|
150
|
+
* @desc
|
|
151
|
+
* - queryClient가 전달되면 내부 singleton보다 전달받은 인스턴스를 우선한다.
|
|
152
|
+
* - queryClientConfig는 queryClient를 직접 전달하지 않을 때만 내부 생성에 사용한다.
|
|
153
|
+
* - JotaiProvider는 이 Provider 하위에서 useQueryClient로 동일 인스턴스를 공유한다.
|
|
65
154
|
* @see https://tanstack.com/query/latest/docs/framework/react/guides/advanced-ssr#prefetching-and-dehydrating-data
|
|
66
155
|
* @see https://tanstack.com/query/latest/docs/framework/react/guides/advanced-ssr#nesting-server-components
|
|
67
156
|
*/
|
|
68
157
|
export function ReactQueryProvider({
|
|
69
158
|
children,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}) {
|
|
159
|
+
queryClient,
|
|
160
|
+
queryClientConfig,
|
|
161
|
+
}: ReactQueryProviderProps) {
|
|
73
162
|
// NOTE: Avoid useState when initializing the query client if you don't
|
|
74
163
|
// have a suspense boundary between this and the code that may
|
|
75
164
|
// suspend because React will throw away the client on the initial
|
|
76
165
|
// render if it suspends and there is no boundary
|
|
77
|
-
|
|
166
|
+
// 외부 주입 client가 있으면 Provider 전체에서 그 인스턴스를 단일 SOT로 사용한다.
|
|
167
|
+
const resolvedQueryClient = queryClient ?? getQueryClient(queryClientConfig);
|
|
78
168
|
|
|
79
169
|
return (
|
|
80
|
-
|
|
170
|
+
// React Query context에 올린 client는 JotaiHydrateAtoms에서도 동일하게 참조된다.
|
|
171
|
+
<QueryClientProvider client={resolvedQueryClient}>
|
|
172
|
+
{children}
|
|
173
|
+
</QueryClientProvider>
|
|
81
174
|
);
|
|
82
175
|
}
|