UNPKG

6.37 kBJavaScriptView Raw
1import { QueryClient, QueryObserver, InfiniteQueryObserver, isCancelledError } from '@tanstack/query-core';
2import { atom } from 'jotai';
3
4const queryClientAtom = atom(new QueryClient());
5
6function atomWithQuery(createQuery, getQueryClient = (get) => get(queryClientAtom)) {
7 const observerAtom = atom((get) => {
8 const queryClient = getQueryClient(get);
9 const defaultedOptions = queryClient.defaultQueryOptions();
10 const observer = new QueryObserver(queryClient, defaultedOptions);
11 return observer;
12 });
13 const queryDataAtom = atom(
14 (get) => {
15 const queryClient = getQueryClient(get);
16 const options = typeof createQuery === "function" ? createQuery(get) : createQuery;
17 const defaultedOptions = queryClient.defaultQueryOptions(options);
18 const observer = get(observerAtom);
19 observer.destroy();
20 observer.setOptions(defaultedOptions);
21 const initialResult = observer.getCurrentResult();
22 let resolve = null;
23 const resultAtom = atom(
24 initialResult.data === void 0 && options.enabled !== false ? new Promise((r) => {
25 resolve = r;
26 }) : initialResult
27 );
28 let setResult = null;
29 let unsubscribe = null;
30 const unsubIfNotMounted = () => {
31 if (!setResult) {
32 unsubscribe == null ? void 0 : unsubscribe();
33 unsubscribe = null;
34 }
35 };
36 const listener = (result) => {
37 if (result.isFetching || !result.isError && result.data === void 0) {
38 return;
39 }
40 if (resolve) {
41 setTimeout(unsubIfNotMounted, 1e3);
42 resolve(result);
43 resolve = null;
44 } else if (setResult) {
45 setResult(result);
46 } else {
47 throw new Error("setting result without mount");
48 }
49 };
50 if (options.enabled !== false) {
51 unsubscribe = observer.subscribe(listener);
52 }
53 resultAtom.onMount = (update) => {
54 setResult = update;
55 if (options.enabled !== false && !unsubscribe) {
56 unsubscribe = observer.subscribe(listener);
57 listener(observer.getCurrentResult());
58 }
59 return () => {
60 setResult = null;
61 unsubscribe == null ? void 0 : unsubscribe();
62 };
63 };
64 return { options, resultAtom, unsubIfNotMounted };
65 },
66 (get, set, action) => {
67 const observer = get(observerAtom);
68 const { options, resultAtom, unsubIfNotMounted } = get(queryDataAtom);
69 if (options.enabled === false) {
70 return;
71 }
72 switch (action.type) {
73 case "refetch": {
74 set(resultAtom, new Promise(() => {
75 }));
76 unsubIfNotMounted();
77 return observer.refetch({ cancelRefetch: true }).then((result) => {
78 set(resultAtom, result);
79 });
80 }
81 }
82 }
83 );
84 const queryAtom = atom(
85 (get) => {
86 const { resultAtom } = get(queryDataAtom);
87 const result = get(resultAtom);
88 if (result.isError) {
89 throw result.error;
90 }
91 return result.data;
92 },
93 (_get, set, action) => set(queryDataAtom, action)
94 );
95 return queryAtom;
96}
97
98function atomWithInfiniteQuery(createQuery, getQueryClient = (get) => get(queryClientAtom)) {
99 const queryDataAtom = atom(
100 (get) => {
101 const queryClient = getQueryClient(get);
102 const options = typeof createQuery === "function" ? createQuery(get) : createQuery;
103 const defaultedOptions = queryClient.defaultQueryOptions(options);
104 const observer = new InfiniteQueryObserver(queryClient, defaultedOptions);
105 const initialResult = observer.getCurrentResult();
106 let resolve = null;
107 const resultAtom = atom(
108 initialResult.data === void 0 && options.enabled !== false ? new Promise((r) => {
109 resolve = r;
110 }) : initialResult
111 );
112 let setResult = () => {
113 throw new Error("setting result without mount");
114 };
115 const state = {
116 isMounted: false,
117 unsubscribe: null
118 };
119 const listener = (result) => {
120 if (result.isFetching || !result.isError && result.data === void 0 || result.isError && isCancelledError(result.error)) {
121 return;
122 }
123 if (resolve) {
124 setTimeout(() => {
125 var _a;
126 if (!state.isMounted) {
127 (_a = state.unsubscribe) == null ? void 0 : _a.call(state);
128 state.unsubscribe = null;
129 }
130 }, 1e3);
131 resolve(result);
132 resolve = null;
133 } else {
134 setResult(result);
135 }
136 };
137 if (options.enabled !== false) {
138 state.unsubscribe = observer.subscribe(listener);
139 }
140 resultAtom.onMount = (update) => {
141 setResult = update;
142 state.isMounted = true;
143 if (options.enabled !== false && !state.unsubscribe) {
144 state.unsubscribe = observer.subscribe(listener);
145 listener(observer.getCurrentResult());
146 }
147 return () => {
148 var _a;
149 return (_a = state.unsubscribe) == null ? void 0 : _a.call(state);
150 };
151 };
152 return { options, resultAtom, observer, state };
153 },
154 (get, set, action) => {
155 var _a;
156 const { options, resultAtom, observer, state } = get(queryDataAtom);
157 if (options.enabled === false) {
158 return;
159 }
160 switch (action.type) {
161 case "refetch": {
162 set(resultAtom, new Promise(() => {
163 }));
164 if (!state.isMounted) {
165 (_a = state.unsubscribe) == null ? void 0 : _a.call(state);
166 state.unsubscribe = null;
167 }
168 observer.refetch(action.payload).then((result) => {
169 set(resultAtom, result);
170 });
171 return;
172 }
173 case "fetchPreviousPage": {
174 observer.fetchPreviousPage();
175 return;
176 }
177 case "fetchNextPage": {
178 observer.fetchNextPage();
179 return;
180 }
181 }
182 }
183 );
184 const queryAtom = atom(
185 (get) => {
186 const { resultAtom } = get(queryDataAtom);
187 const result = get(resultAtom);
188 if (result.isError) {
189 throw result.error;
190 }
191 return result.data;
192 },
193 (_get, set, action) => set(queryDataAtom, action)
194 );
195 return queryAtom;
196}
197
198export { atomWithInfiniteQuery, atomWithQuery, queryClientAtom };