@tanstack/solid-query 5.29.3 → 5.30.1

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/build/dev.cjs CHANGED
@@ -5,8 +5,7 @@ var solidJs = require('solid-js');
5
5
  var web = require('solid-js/web');
6
6
  var store = require('solid-js/store');
7
7
 
8
- // src/setBatchUpdatesFn.ts
9
- queryCore.notifyManager.setBatchNotifyFunction(solidJs.batch);
8
+ // src/index.ts
10
9
  exports.QueryClient = class QueryClient extends queryCore.QueryClient {
11
10
  constructor(config = {}) {
12
11
  super(config);
@@ -103,9 +102,8 @@ function createBaseQuery(options, Observer, queryClient) {
103
102
  const [observer, setObserver] = solidJs.createSignal(
104
103
  new Observer(client(), defaultedOptions())
105
104
  );
106
- const [state, setState] = store.createStore(
107
- observer().getOptimisticResult(defaultedOptions())
108
- );
105
+ let observerResult = observer().getOptimisticResult(defaultedOptions());
106
+ const [state, setState] = store.createStore(observerResult);
109
107
  const createServerSubscriber = (resolve, reject) => {
110
108
  return observer().subscribe((result) => {
111
109
  queryCore.notifyManager.batchCalls(() => {
@@ -130,32 +128,34 @@ function createBaseQuery(options, Observer, queryClient) {
130
128
  const createClientSubscriber = () => {
131
129
  const obs = observer();
132
130
  return obs.subscribe((result) => {
133
- queryCore.notifyManager.batchCalls(() => {
134
- const reconcileOptions = obs.options.reconcile;
135
- if (!queryResource.error && queryResource()?.data && result.data && !queryResource.loading) {
136
- setState((store) => {
137
- return reconcileFn(
138
- store,
139
- result,
140
- reconcileOptions === void 0 ? false : reconcileOptions
141
- );
142
- });
143
- mutate(state);
144
- } else {
145
- setState((store) => {
146
- return reconcileFn(
147
- store,
148
- result,
149
- reconcileOptions === void 0 ? false : reconcileOptions
150
- );
151
- });
152
- refetch();
153
- }
154
- })();
131
+ observerResult = result;
132
+ queueMicrotask(() => refetch());
155
133
  });
156
134
  };
135
+ function setStateWithReconciliation(res) {
136
+ const reconcileOptions = observer().options.reconcile;
137
+ setState((store) => {
138
+ return reconcileFn(
139
+ store,
140
+ res,
141
+ reconcileOptions === void 0 ? false : reconcileOptions
142
+ );
143
+ });
144
+ }
145
+ function createDeepSignal() {
146
+ return [
147
+ () => state,
148
+ (v) => {
149
+ const unwrapped = store.unwrap(state);
150
+ if (typeof v === "function") {
151
+ v = v(unwrapped);
152
+ }
153
+ setStateWithReconciliation(v);
154
+ }
155
+ ];
156
+ }
157
157
  let unsubscribe = null;
158
- const [queryResource, { refetch, mutate }] = solidJs.createResource(
158
+ const [queryResource, { refetch }] = solidJs.createResource(
159
159
  () => {
160
160
  const obs = observer();
161
161
  return new Promise((resolve, reject) => {
@@ -165,18 +165,22 @@ function createBaseQuery(options, Observer, queryClient) {
165
165
  unsubscribe = createClientSubscriber();
166
166
  }
167
167
  obs.updateResult();
168
- if (!state.isLoading) {
168
+ if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
169
+ observerResult.error,
170
+ obs.getCurrentQuery()
171
+ ])) {
172
+ setStateWithReconciliation(observerResult);
173
+ return reject(observerResult.error);
174
+ }
175
+ if (!observerResult.isLoading) {
169
176
  const query = obs.getCurrentQuery();
170
- resolve(hydratableObserverResult(query, state));
177
+ return resolve(hydratableObserverResult(query, observerResult));
171
178
  }
179
+ setStateWithReconciliation(observerResult);
172
180
  });
173
181
  },
174
182
  {
175
- initialValue: state,
176
- // If initialData is provided, we resolve the resource immediately
177
- get ssrLoadFrom() {
178
- return options().initialData ? "initial" : "server";
179
- },
183
+ storage: createDeepSignal,
180
184
  get deferStream() {
181
185
  return options().deferStream;
182
186
  },
@@ -254,29 +258,21 @@ function createBaseQuery(options, Observer, queryClient) {
254
258
  [observer, defaultedOptions],
255
259
  ([obs, opts]) => {
256
260
  obs.setOptions(opts);
257
- setState(obs.getOptimisticResult(opts));
261
+ setStateWithReconciliation(obs.getOptimisticResult(opts));
258
262
  },
259
263
  { defer: true }
260
264
  )
261
265
  );
262
- solidJs.createComputed(
263
- solidJs.on(
264
- () => state.status,
265
- () => {
266
- const obs = observer();
267
- if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
268
- state.error,
269
- obs.getCurrentQuery()
270
- ])) {
271
- throw state.error;
272
- }
273
- }
274
- )
275
- );
276
266
  const handler = {
277
267
  get(target, prop) {
278
- const val = queryResource()?.[prop];
279
- return val !== void 0 ? val : Reflect.get(target, prop);
268
+ if (prop === "data") {
269
+ const opts = observer().options;
270
+ if (opts.placeholderData) {
271
+ return queryResource.latest?.data;
272
+ }
273
+ return queryResource()?.data;
274
+ }
275
+ return Reflect.get(target, prop);
280
276
  }
281
277
  };
282
278
  return new Proxy(state, handler);
package/build/dev.js CHANGED
@@ -1,11 +1,10 @@
1
- import { notifyManager, QueryClient as QueryClient$1, MutationObserver, replaceEqualDeep, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core';
1
+ import { QueryClient as QueryClient$1, MutationObserver, replaceEqualDeep, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver, notifyManager } from '@tanstack/query-core';
2
2
  export * from '@tanstack/query-core';
3
- import { batch, createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, createEffect, mergeProps, createResource, onMount } from 'solid-js';
3
+ import { createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, createEffect, mergeProps, createResource, batch, onMount } from 'solid-js';
4
4
  import { createComponent, isServer } from 'solid-js/web';
5
5
  import { createStore, unwrap, reconcile } from 'solid-js/store';
6
6
 
7
- // src/setBatchUpdatesFn.ts
8
- notifyManager.setBatchNotifyFunction(batch);
7
+ // src/index.ts
9
8
  var QueryClient = class extends QueryClient$1 {
10
9
  constructor(config = {}) {
11
10
  super(config);
@@ -102,9 +101,8 @@ function createBaseQuery(options, Observer, queryClient) {
102
101
  const [observer, setObserver] = createSignal(
103
102
  new Observer(client(), defaultedOptions())
104
103
  );
105
- const [state, setState] = createStore(
106
- observer().getOptimisticResult(defaultedOptions())
107
- );
104
+ let observerResult = observer().getOptimisticResult(defaultedOptions());
105
+ const [state, setState] = createStore(observerResult);
108
106
  const createServerSubscriber = (resolve, reject) => {
109
107
  return observer().subscribe((result) => {
110
108
  notifyManager.batchCalls(() => {
@@ -129,32 +127,34 @@ function createBaseQuery(options, Observer, queryClient) {
129
127
  const createClientSubscriber = () => {
130
128
  const obs = observer();
131
129
  return obs.subscribe((result) => {
132
- notifyManager.batchCalls(() => {
133
- const reconcileOptions = obs.options.reconcile;
134
- if (!queryResource.error && queryResource()?.data && result.data && !queryResource.loading) {
135
- setState((store) => {
136
- return reconcileFn(
137
- store,
138
- result,
139
- reconcileOptions === void 0 ? false : reconcileOptions
140
- );
141
- });
142
- mutate(state);
143
- } else {
144
- setState((store) => {
145
- return reconcileFn(
146
- store,
147
- result,
148
- reconcileOptions === void 0 ? false : reconcileOptions
149
- );
150
- });
151
- refetch();
152
- }
153
- })();
130
+ observerResult = result;
131
+ queueMicrotask(() => refetch());
154
132
  });
155
133
  };
134
+ function setStateWithReconciliation(res) {
135
+ const reconcileOptions = observer().options.reconcile;
136
+ setState((store) => {
137
+ return reconcileFn(
138
+ store,
139
+ res,
140
+ reconcileOptions === void 0 ? false : reconcileOptions
141
+ );
142
+ });
143
+ }
144
+ function createDeepSignal() {
145
+ return [
146
+ () => state,
147
+ (v) => {
148
+ const unwrapped = unwrap(state);
149
+ if (typeof v === "function") {
150
+ v = v(unwrapped);
151
+ }
152
+ setStateWithReconciliation(v);
153
+ }
154
+ ];
155
+ }
156
156
  let unsubscribe = null;
157
- const [queryResource, { refetch, mutate }] = createResource(
157
+ const [queryResource, { refetch }] = createResource(
158
158
  () => {
159
159
  const obs = observer();
160
160
  return new Promise((resolve, reject) => {
@@ -164,18 +164,22 @@ function createBaseQuery(options, Observer, queryClient) {
164
164
  unsubscribe = createClientSubscriber();
165
165
  }
166
166
  obs.updateResult();
167
- if (!state.isLoading) {
167
+ if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
168
+ observerResult.error,
169
+ obs.getCurrentQuery()
170
+ ])) {
171
+ setStateWithReconciliation(observerResult);
172
+ return reject(observerResult.error);
173
+ }
174
+ if (!observerResult.isLoading) {
168
175
  const query = obs.getCurrentQuery();
169
- resolve(hydratableObserverResult(query, state));
176
+ return resolve(hydratableObserverResult(query, observerResult));
170
177
  }
178
+ setStateWithReconciliation(observerResult);
171
179
  });
172
180
  },
173
181
  {
174
- initialValue: state,
175
- // If initialData is provided, we resolve the resource immediately
176
- get ssrLoadFrom() {
177
- return options().initialData ? "initial" : "server";
178
- },
182
+ storage: createDeepSignal,
179
183
  get deferStream() {
180
184
  return options().deferStream;
181
185
  },
@@ -253,29 +257,21 @@ function createBaseQuery(options, Observer, queryClient) {
253
257
  [observer, defaultedOptions],
254
258
  ([obs, opts]) => {
255
259
  obs.setOptions(opts);
256
- setState(obs.getOptimisticResult(opts));
260
+ setStateWithReconciliation(obs.getOptimisticResult(opts));
257
261
  },
258
262
  { defer: true }
259
263
  )
260
264
  );
261
- createComputed(
262
- on(
263
- () => state.status,
264
- () => {
265
- const obs = observer();
266
- if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
267
- state.error,
268
- obs.getCurrentQuery()
269
- ])) {
270
- throw state.error;
271
- }
272
- }
273
- )
274
- );
275
265
  const handler = {
276
266
  get(target, prop) {
277
- const val = queryResource()?.[prop];
278
- return val !== void 0 ? val : Reflect.get(target, prop);
267
+ if (prop === "data") {
268
+ const opts = observer().options;
269
+ if (opts.placeholderData) {
270
+ return queryResource.latest?.data;
271
+ }
272
+ return queryResource()?.data;
273
+ }
274
+ return Reflect.get(target, prop);
279
275
  }
280
276
  };
281
277
  return new Proxy(state, handler);
package/build/index.cjs CHANGED
@@ -5,8 +5,7 @@ var solidJs = require('solid-js');
5
5
  var web = require('solid-js/web');
6
6
  var store = require('solid-js/store');
7
7
 
8
- // src/setBatchUpdatesFn.ts
9
- queryCore.notifyManager.setBatchNotifyFunction(solidJs.batch);
8
+ // src/index.ts
10
9
  exports.QueryClient = class QueryClient extends queryCore.QueryClient {
11
10
  constructor(config = {}) {
12
11
  super(config);
@@ -103,9 +102,8 @@ function createBaseQuery(options, Observer, queryClient) {
103
102
  const [observer, setObserver] = solidJs.createSignal(
104
103
  new Observer(client(), defaultedOptions())
105
104
  );
106
- const [state, setState] = store.createStore(
107
- observer().getOptimisticResult(defaultedOptions())
108
- );
105
+ let observerResult = observer().getOptimisticResult(defaultedOptions());
106
+ const [state, setState] = store.createStore(observerResult);
109
107
  const createServerSubscriber = (resolve, reject) => {
110
108
  return observer().subscribe((result) => {
111
109
  queryCore.notifyManager.batchCalls(() => {
@@ -130,32 +128,34 @@ function createBaseQuery(options, Observer, queryClient) {
130
128
  const createClientSubscriber = () => {
131
129
  const obs = observer();
132
130
  return obs.subscribe((result) => {
133
- queryCore.notifyManager.batchCalls(() => {
134
- const reconcileOptions = obs.options.reconcile;
135
- if (!queryResource.error && queryResource()?.data && result.data && !queryResource.loading) {
136
- setState((store) => {
137
- return reconcileFn(
138
- store,
139
- result,
140
- reconcileOptions === void 0 ? false : reconcileOptions
141
- );
142
- });
143
- mutate(state);
144
- } else {
145
- setState((store) => {
146
- return reconcileFn(
147
- store,
148
- result,
149
- reconcileOptions === void 0 ? false : reconcileOptions
150
- );
151
- });
152
- refetch();
153
- }
154
- })();
131
+ observerResult = result;
132
+ queueMicrotask(() => refetch());
155
133
  });
156
134
  };
135
+ function setStateWithReconciliation(res) {
136
+ const reconcileOptions = observer().options.reconcile;
137
+ setState((store) => {
138
+ return reconcileFn(
139
+ store,
140
+ res,
141
+ reconcileOptions === void 0 ? false : reconcileOptions
142
+ );
143
+ });
144
+ }
145
+ function createDeepSignal() {
146
+ return [
147
+ () => state,
148
+ (v) => {
149
+ const unwrapped = store.unwrap(state);
150
+ if (typeof v === "function") {
151
+ v = v(unwrapped);
152
+ }
153
+ setStateWithReconciliation(v);
154
+ }
155
+ ];
156
+ }
157
157
  let unsubscribe = null;
158
- const [queryResource, { refetch, mutate }] = solidJs.createResource(
158
+ const [queryResource, { refetch }] = solidJs.createResource(
159
159
  () => {
160
160
  const obs = observer();
161
161
  return new Promise((resolve, reject) => {
@@ -165,18 +165,22 @@ function createBaseQuery(options, Observer, queryClient) {
165
165
  unsubscribe = createClientSubscriber();
166
166
  }
167
167
  obs.updateResult();
168
- if (!state.isLoading) {
168
+ if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
169
+ observerResult.error,
170
+ obs.getCurrentQuery()
171
+ ])) {
172
+ setStateWithReconciliation(observerResult);
173
+ return reject(observerResult.error);
174
+ }
175
+ if (!observerResult.isLoading) {
169
176
  const query = obs.getCurrentQuery();
170
- resolve(hydratableObserverResult(query, state));
177
+ return resolve(hydratableObserverResult(query, observerResult));
171
178
  }
179
+ setStateWithReconciliation(observerResult);
172
180
  });
173
181
  },
174
182
  {
175
- initialValue: state,
176
- // If initialData is provided, we resolve the resource immediately
177
- get ssrLoadFrom() {
178
- return options().initialData ? "initial" : "server";
179
- },
183
+ storage: createDeepSignal,
180
184
  get deferStream() {
181
185
  return options().deferStream;
182
186
  },
@@ -254,29 +258,21 @@ function createBaseQuery(options, Observer, queryClient) {
254
258
  [observer, defaultedOptions],
255
259
  ([obs, opts]) => {
256
260
  obs.setOptions(opts);
257
- setState(obs.getOptimisticResult(opts));
261
+ setStateWithReconciliation(obs.getOptimisticResult(opts));
258
262
  },
259
263
  { defer: true }
260
264
  )
261
265
  );
262
- solidJs.createComputed(
263
- solidJs.on(
264
- () => state.status,
265
- () => {
266
- const obs = observer();
267
- if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
268
- state.error,
269
- obs.getCurrentQuery()
270
- ])) {
271
- throw state.error;
272
- }
273
- }
274
- )
275
- );
276
266
  const handler = {
277
267
  get(target, prop) {
278
- const val = queryResource()?.[prop];
279
- return val !== void 0 ? val : Reflect.get(target, prop);
268
+ if (prop === "data") {
269
+ const opts = observer().options;
270
+ if (opts.placeholderData) {
271
+ return queryResource.latest?.data;
272
+ }
273
+ return queryResource()?.data;
274
+ }
275
+ return Reflect.get(target, prop);
280
276
  }
281
277
  };
282
278
  return new Proxy(state, handler);
package/build/index.js CHANGED
@@ -1,11 +1,10 @@
1
- import { notifyManager, QueryClient as QueryClient$1, MutationObserver, replaceEqualDeep, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core';
1
+ import { QueryClient as QueryClient$1, MutationObserver, replaceEqualDeep, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver, notifyManager } from '@tanstack/query-core';
2
2
  export * from '@tanstack/query-core';
3
- import { batch, createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, createEffect, mergeProps, createResource, onMount } from 'solid-js';
3
+ import { createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, createEffect, mergeProps, createResource, batch, onMount } from 'solid-js';
4
4
  import { createComponent, isServer } from 'solid-js/web';
5
5
  import { createStore, unwrap, reconcile } from 'solid-js/store';
6
6
 
7
- // src/setBatchUpdatesFn.ts
8
- notifyManager.setBatchNotifyFunction(batch);
7
+ // src/index.ts
9
8
  var QueryClient = class extends QueryClient$1 {
10
9
  constructor(config = {}) {
11
10
  super(config);
@@ -102,9 +101,8 @@ function createBaseQuery(options, Observer, queryClient) {
102
101
  const [observer, setObserver] = createSignal(
103
102
  new Observer(client(), defaultedOptions())
104
103
  );
105
- const [state, setState] = createStore(
106
- observer().getOptimisticResult(defaultedOptions())
107
- );
104
+ let observerResult = observer().getOptimisticResult(defaultedOptions());
105
+ const [state, setState] = createStore(observerResult);
108
106
  const createServerSubscriber = (resolve, reject) => {
109
107
  return observer().subscribe((result) => {
110
108
  notifyManager.batchCalls(() => {
@@ -129,32 +127,34 @@ function createBaseQuery(options, Observer, queryClient) {
129
127
  const createClientSubscriber = () => {
130
128
  const obs = observer();
131
129
  return obs.subscribe((result) => {
132
- notifyManager.batchCalls(() => {
133
- const reconcileOptions = obs.options.reconcile;
134
- if (!queryResource.error && queryResource()?.data && result.data && !queryResource.loading) {
135
- setState((store) => {
136
- return reconcileFn(
137
- store,
138
- result,
139
- reconcileOptions === void 0 ? false : reconcileOptions
140
- );
141
- });
142
- mutate(state);
143
- } else {
144
- setState((store) => {
145
- return reconcileFn(
146
- store,
147
- result,
148
- reconcileOptions === void 0 ? false : reconcileOptions
149
- );
150
- });
151
- refetch();
152
- }
153
- })();
130
+ observerResult = result;
131
+ queueMicrotask(() => refetch());
154
132
  });
155
133
  };
134
+ function setStateWithReconciliation(res) {
135
+ const reconcileOptions = observer().options.reconcile;
136
+ setState((store) => {
137
+ return reconcileFn(
138
+ store,
139
+ res,
140
+ reconcileOptions === void 0 ? false : reconcileOptions
141
+ );
142
+ });
143
+ }
144
+ function createDeepSignal() {
145
+ return [
146
+ () => state,
147
+ (v) => {
148
+ const unwrapped = unwrap(state);
149
+ if (typeof v === "function") {
150
+ v = v(unwrapped);
151
+ }
152
+ setStateWithReconciliation(v);
153
+ }
154
+ ];
155
+ }
156
156
  let unsubscribe = null;
157
- const [queryResource, { refetch, mutate }] = createResource(
157
+ const [queryResource, { refetch }] = createResource(
158
158
  () => {
159
159
  const obs = observer();
160
160
  return new Promise((resolve, reject) => {
@@ -164,18 +164,22 @@ function createBaseQuery(options, Observer, queryClient) {
164
164
  unsubscribe = createClientSubscriber();
165
165
  }
166
166
  obs.updateResult();
167
- if (!state.isLoading) {
167
+ if (observerResult.isError && !observerResult.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
168
+ observerResult.error,
169
+ obs.getCurrentQuery()
170
+ ])) {
171
+ setStateWithReconciliation(observerResult);
172
+ return reject(observerResult.error);
173
+ }
174
+ if (!observerResult.isLoading) {
168
175
  const query = obs.getCurrentQuery();
169
- resolve(hydratableObserverResult(query, state));
176
+ return resolve(hydratableObserverResult(query, observerResult));
170
177
  }
178
+ setStateWithReconciliation(observerResult);
171
179
  });
172
180
  },
173
181
  {
174
- initialValue: state,
175
- // If initialData is provided, we resolve the resource immediately
176
- get ssrLoadFrom() {
177
- return options().initialData ? "initial" : "server";
178
- },
182
+ storage: createDeepSignal,
179
183
  get deferStream() {
180
184
  return options().deferStream;
181
185
  },
@@ -253,29 +257,21 @@ function createBaseQuery(options, Observer, queryClient) {
253
257
  [observer, defaultedOptions],
254
258
  ([obs, opts]) => {
255
259
  obs.setOptions(opts);
256
- setState(obs.getOptimisticResult(opts));
260
+ setStateWithReconciliation(obs.getOptimisticResult(opts));
257
261
  },
258
262
  { defer: true }
259
263
  )
260
264
  );
261
- createComputed(
262
- on(
263
- () => state.status,
264
- () => {
265
- const obs = observer();
266
- if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [
267
- state.error,
268
- obs.getCurrentQuery()
269
- ])) {
270
- throw state.error;
271
- }
272
- }
273
- )
274
- );
275
265
  const handler = {
276
266
  get(target, prop) {
277
- const val = queryResource()?.[prop];
278
- return val !== void 0 ? val : Reflect.get(target, prop);
267
+ if (prop === "data") {
268
+ const opts = observer().options;
269
+ if (opts.placeholderData) {
270
+ return queryResource.latest?.data;
271
+ }
272
+ return queryResource()?.data;
273
+ }
274
+ return Reflect.get(target, prop);
279
275
  }
280
276
  };
281
277
  return new Proxy(state, handler);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/solid-query",
3
- "version": "5.29.3",
3
+ "version": "5.30.1",
4
4
  "description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -39,9 +39,6 @@
39
39
  "default": "./build/index.cjs"
40
40
  }
41
41
  },
42
- "sideEffects": [
43
- "./src/setBatchUpdatesFn.ts"
44
- ],
45
42
  "files": [
46
43
  "build",
47
44
  "src"
@@ -2407,6 +2407,7 @@ describe('createQuery', () => {
2407
2407
 
2408
2408
  return (
2409
2409
  <div>
2410
+ <h1>{state.data}</h1>
2410
2411
  <h1>{state.status}</h1>
2411
2412
  <h2>{state.error?.message}</h2>
2412
2413
  </div>
@@ -2426,6 +2427,124 @@ describe('createQuery', () => {
2426
2427
  consoleMock.mockRestore()
2427
2428
  })
2428
2429
 
2430
+ it('should throw error inside the same component if queryFn throws and throwOnError is in use', async () => {
2431
+ const key = queryKey()
2432
+
2433
+ const consoleMock = vi
2434
+ .spyOn(console, 'error')
2435
+ .mockImplementation(() => undefined)
2436
+
2437
+ function Page() {
2438
+ const state = createQuery(() => ({
2439
+ queryKey: key,
2440
+ queryFn: () => Promise.reject(new Error('Error test')),
2441
+ retry: false,
2442
+ throwOnError: true,
2443
+ }))
2444
+
2445
+ return (
2446
+ <div>
2447
+ <ErrorBoundary fallback={() => <div>error boundary</div>}>
2448
+ <h1>{state.data}</h1>
2449
+ <h1>{state.status}</h1>
2450
+ <h2>{state.error?.message}</h2>
2451
+ </ErrorBoundary>
2452
+ </div>
2453
+ )
2454
+ }
2455
+
2456
+ const rendered = render(() => (
2457
+ <QueryClientProvider client={queryClient}>
2458
+ <Page />
2459
+ </QueryClientProvider>
2460
+ ))
2461
+
2462
+ await waitFor(() => rendered.getByText('error boundary'))
2463
+
2464
+ consoleMock.mockRestore()
2465
+ })
2466
+
2467
+ it('should throw error inside the same component if queryFn throws and show the correct error message', async () => {
2468
+ const key = queryKey()
2469
+
2470
+ const consoleMock = vi
2471
+ .spyOn(console, 'error')
2472
+ .mockImplementation(() => undefined)
2473
+
2474
+ function Page() {
2475
+ const state = createQuery(() => ({
2476
+ queryKey: key,
2477
+ queryFn: () => Promise.reject(new Error('Error test')),
2478
+ retry: false,
2479
+ throwOnError: true,
2480
+ }))
2481
+
2482
+ return (
2483
+ <div>
2484
+ <ErrorBoundary
2485
+ fallback={(err) => <div>Fallback error: {err.message}</div>}
2486
+ >
2487
+ <h1>{state.data}</h1>
2488
+ <h1>{state.status}</h1>
2489
+ <h2>{state.error?.message}</h2>
2490
+ </ErrorBoundary>
2491
+ </div>
2492
+ )
2493
+ }
2494
+
2495
+ const rendered = render(() => (
2496
+ <QueryClientProvider client={queryClient}>
2497
+ <Page />
2498
+ </QueryClientProvider>
2499
+ ))
2500
+
2501
+ await waitFor(() => rendered.getByText('Fallback error: Error test'))
2502
+
2503
+ consoleMock.mockRestore()
2504
+ })
2505
+
2506
+ it('should show the correct error message on the error property when accessed outside error boundary', async () => {
2507
+ const key = queryKey()
2508
+
2509
+ const consoleMock = vi
2510
+ .spyOn(console, 'error')
2511
+ .mockImplementation(() => undefined)
2512
+
2513
+ function Page() {
2514
+ const state = createQuery(() => ({
2515
+ queryKey: key,
2516
+ queryFn: () => Promise.reject(new Error('Error test')),
2517
+ retry: false,
2518
+ throwOnError: true,
2519
+ }))
2520
+
2521
+ return (
2522
+ <div>
2523
+ <h2>Outside error boundary: {state.error?.message}</h2>
2524
+ <ErrorBoundary
2525
+ fallback={(err) => <div>Fallback error: {err.message}</div>}
2526
+ >
2527
+ <h1>{state.data}</h1>
2528
+ <h1>{state.status}</h1>
2529
+ </ErrorBoundary>
2530
+ </div>
2531
+ )
2532
+ }
2533
+
2534
+ const rendered = render(() => (
2535
+ <QueryClientProvider client={queryClient}>
2536
+ <Page />
2537
+ </QueryClientProvider>
2538
+ ))
2539
+
2540
+ await waitFor(() =>
2541
+ rendered.getByText('Outside error boundary: Error test'),
2542
+ )
2543
+ await waitFor(() => rendered.getByText('Fallback error: Error test'))
2544
+
2545
+ consoleMock.mockRestore()
2546
+ })
2547
+
2429
2548
  it('should update with data if we observe no properties and throwOnError', async () => {
2430
2549
  const key = queryKey()
2431
2550
 
@@ -2491,7 +2610,7 @@ describe('createQuery', () => {
2491
2610
  const key = queryKey()
2492
2611
 
2493
2612
  function Page() {
2494
- const state = createQuery<unknown, Error>(() => ({
2613
+ const state = createQuery(() => ({
2495
2614
  queryKey: key,
2496
2615
  queryFn: () => Promise.reject(new Error('Remote Error')),
2497
2616
  retry: false,
@@ -2500,6 +2619,7 @@ describe('createQuery', () => {
2500
2619
 
2501
2620
  return (
2502
2621
  <div>
2622
+ <div>{state.data}</div>
2503
2623
  <h1>{state.status}</h1>
2504
2624
  <h2>{state.error?.message ?? ''}</h2>
2505
2625
  </div>
@@ -16,7 +16,7 @@ import { useQueryClient } from './QueryClientProvider'
16
16
  import { shouldThrowError } from './utils'
17
17
  import { useIsRestoring } from './isRestoring'
18
18
  import type { CreateBaseQueryOptions } from './types'
19
- import type { Accessor } from 'solid-js'
19
+ import type { Accessor, Signal } from 'solid-js'
20
20
  import type { QueryClient } from './QueryClient'
21
21
  import type {
22
22
  InfiniteQueryObserverResult,
@@ -144,9 +144,9 @@ export function createBaseQuery<
144
144
  new Observer(client(), defaultedOptions()),
145
145
  )
146
146
 
147
- const [state, setState] = createStore<QueryObserverResult<TData, TError>>(
148
- observer().getOptimisticResult(defaultedOptions()),
149
- )
147
+ let observerResult = observer().getOptimisticResult(defaultedOptions())
148
+ const [state, setState] =
149
+ createStore<QueryObserverResult<TData, TError>>(observerResult)
150
150
 
151
151
  const createServerSubscriber = (
152
152
  resolve: (
@@ -180,49 +180,43 @@ export function createBaseQuery<
180
180
  const createClientSubscriber = () => {
181
181
  const obs = observer()
182
182
  return obs.subscribe((result) => {
183
- notifyManager.batchCalls(() => {
184
- // @ts-expect-error - This will error because the reconcile option does not
185
- // exist on the query-core QueryObserverResult type
186
- const reconcileOptions = obs.options.reconcile
183
+ observerResult = result
184
+ queueMicrotask(() => refetch())
185
+ })
186
+ }
187
187
 
188
- // If the query has data we don't suspend but instead mutate the resource
189
- // This could happen when placeholderData/initialData is defined
190
- if (
191
- !queryResource.error &&
192
- queryResource()?.data &&
193
- result.data &&
194
- !queryResource.loading
195
- ) {
196
- setState((store) => {
197
- return reconcileFn(
198
- store,
199
- result,
200
- reconcileOptions === undefined ? false : reconcileOptions,
201
- )
202
- })
203
- mutate(state)
204
- } else {
205
- setState((store) => {
206
- return reconcileFn(
207
- store,
208
- result,
209
- reconcileOptions === undefined ? false : reconcileOptions,
210
- )
211
- })
212
- refetch()
213
- }
214
- })()
188
+ function setStateWithReconciliation(res: typeof observerResult) {
189
+ // @ts-expect-error - Reconcile option is not correctly typed internally
190
+ const reconcileOptions = observer().options.reconcile
191
+
192
+ setState((store) => {
193
+ return reconcileFn(
194
+ store,
195
+ res,
196
+ reconcileOptions === undefined ? false : reconcileOptions,
197
+ )
215
198
  })
216
199
  }
217
200
 
201
+ function createDeepSignal<T>(): Signal<T> {
202
+ return [
203
+ () => state,
204
+ (v: T) => {
205
+ const unwrapped = unwrap(state)
206
+ if (typeof v === 'function') {
207
+ v = v(unwrapped)
208
+ }
209
+ setStateWithReconciliation(v as any)
210
+ },
211
+ ] as Signal<T>
212
+ }
213
+
218
214
  /**
219
215
  * Unsubscribe is set lazily, so that we can subscribe after hydration when needed.
220
216
  */
221
217
  let unsubscribe: (() => void) | null = null
222
218
 
223
- const [queryResource, { refetch, mutate }] = createResource<
224
- ResourceData | undefined
225
- >(
219
+ const [queryResource, { refetch }] = createResource<ResourceData | undefined>(
226
220
  () => {
227
221
  const obs = observer()
228
222
  return new Promise((resolve, reject) => {
@@ -233,19 +227,28 @@ export function createBaseQuery<
233
227
  }
234
228
  obs.updateResult()
235
229
 
236
- if (!state.isLoading) {
230
+ if (
231
+ observerResult.isError &&
232
+ !observerResult.isFetching &&
233
+ !isRestoring() &&
234
+ shouldThrowError(obs.options.throwOnError, [
235
+ observerResult.error,
236
+ obs.getCurrentQuery(),
237
+ ])
238
+ ) {
239
+ setStateWithReconciliation(observerResult)
240
+ return reject(observerResult.error)
241
+ }
242
+ if (!observerResult.isLoading) {
237
243
  const query = obs.getCurrentQuery()
238
- resolve(hydratableObserverResult(query, state))
244
+ return resolve(hydratableObserverResult(query, observerResult))
239
245
  }
246
+
247
+ setStateWithReconciliation(observerResult)
240
248
  })
241
249
  },
242
250
  {
243
- initialValue: state,
244
-
245
- // If initialData is provided, we resolve the resource immediately
246
- get ssrLoadFrom() {
247
- return options().initialData ? 'initial' : 'server'
248
- },
251
+ storage: createDeepSignal,
249
252
 
250
253
  get deferStream() {
251
254
  return options().deferStream
@@ -338,39 +341,25 @@ export function createBaseQuery<
338
341
  [observer, defaultedOptions],
339
342
  ([obs, opts]) => {
340
343
  obs.setOptions(opts)
341
- setState(obs.getOptimisticResult(opts))
344
+ setStateWithReconciliation(obs.getOptimisticResult(opts))
342
345
  },
343
346
  { defer: true },
344
347
  ),
345
348
  )
346
349
 
347
- createComputed(
348
- on(
349
- () => state.status,
350
- () => {
351
- const obs = observer()
352
- if (
353
- state.isError &&
354
- !state.isFetching &&
355
- !isRestoring() &&
356
- shouldThrowError(obs.options.throwOnError, [
357
- state.error,
358
- obs.getCurrentQuery(),
359
- ])
360
- ) {
361
- throw state.error
362
- }
363
- },
364
- ),
365
- )
366
-
367
350
  const handler = {
368
351
  get(
369
352
  target: QueryObserverResult<TData, TError>,
370
353
  prop: keyof QueryObserverResult<TData, TError>,
371
354
  ): any {
372
- const val = queryResource()?.[prop]
373
- return val !== undefined ? val : Reflect.get(target, prop)
355
+ if (prop === 'data') {
356
+ const opts = observer().options
357
+ if (opts.placeholderData) {
358
+ return queryResource.latest?.data
359
+ }
360
+ return queryResource()?.data
361
+ }
362
+ return Reflect.get(target, prop)
374
363
  },
375
364
  }
376
365
 
package/src/index.ts CHANGED
@@ -1,8 +1,5 @@
1
1
  /* istanbul ignore file */
2
2
 
3
- // Side Effects
4
- import './setBatchUpdatesFn'
5
-
6
3
  // Re-export core
7
4
  export * from '@tanstack/query-core'
8
5
 
@@ -1,4 +0,0 @@
1
- import { notifyManager } from '@tanstack/query-core'
2
- import { batch } from 'solid-js'
3
-
4
- notifyManager.setBatchNotifyFunction(batch)