Skip to content

Commit

Permalink
Merge branch 'main' into perf/avoid-unnecessary-deep-watch
Browse files Browse the repository at this point in the history
  • Loading branch information
DamianOsipiuk committed Sep 7, 2023
2 parents ca720aa + 423bcf0 commit 731bba6
Show file tree
Hide file tree
Showing 33 changed files with 297 additions and 170 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- 'main'
- 'alpha'
- 'beta'
- 'rc'

concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
Expand All @@ -22,7 +23,7 @@ env:

jobs:
test-and-publish:
if: github.repository == 'TanStack/query' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/alpha' || github.ref == 'refs/heads/beta')
if: github.repository == 'TanStack/query' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/alpha' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/rc')
name: 'Test & Publish'
runs-on: ubuntu-latest
steps:
Expand Down
8 changes: 7 additions & 1 deletion docs/react/community/suspensive-react-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ const Example = () => {

Now, we can concentrate component as any fetching will be always success in component.

### More Information
### useSuspenseQuery is Official API now! (from v5)

@suspensive/react-query provides not only [useSuspenseQuery](https://suspensive.org/docs/react-query/src/useSuspenseQuery.i18n), also [useSuspenseQueries](https://suspensive.org/docs/react-query/src/useSuspenseQueries.i18n), [useSuspenseInfiniteQuery](https://suspensive.org/docs/react-query/src/useSuspenseInfiniteQuery.i18n). From @tanstack/react-query v5 provides [official public hook apis for suspense](https://tanstack.com/query/v5/docs/react/guides/suspense) like @suspensive/react-query's hooks. If want to use them early in v4, use this @suspensive/react-query first.

Check the complete documentation on [Suspensive Official Docs Site](https://suspensive.org/) and also welcome Pull Request on [Suspensive GitHub](https://github.com/suspensive/react)




18 changes: 18 additions & 0 deletions docs/react/guides/infinite-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ function Projects() {

[//]: # 'Example'

It's essential to understand that calling `fetchNextPage` while an ongoing fetch is in progress runs the risk of overwriting data refreshes happening in the background. This situation becomes particularly critical when rendering a list and triggering `fetchNextPage` simultaneously.

Remember, there can only be a single ongoing fetch for an InfiniteQuery. A single cache entry is shared for all pages, attempting to fetch twice simultaneously might lead to data overwrites.

If you intend to enable simultaneous fetching, you can utilize the `{ cancelRefetch: false }` option (default: true) within `fetchNextPage`.

To ensure a seamless querying process without conflicts, it's highly recommended to verify that the query is not in an `isFetching` state, especially if the user won't directly control that call.

[//]: # 'Example1'

```jsx
<List
onEndReached={() => !isFetching && fetchNextPage()}
/>
```

[//]: # 'Example1'

## What happens when an infinite query needs to be refetched?

When an infinite query becomes `stale` and needs to be refetched, each group is fetched `sequentially`, starting from the first one. This ensures that even if the underlying data is mutated, we're not using stale cursors and potentially getting duplicates or skipping records. If an infinite query's results are ever removed from the queryCache, the pagination restarts at the initial state with only the initial group being requested.
Expand Down
2 changes: 1 addition & 1 deletion docs/react/guides/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ TypeScript will also narrow the type of `data` correctly if you've checked for `

### FetchStatus

In addition to the `status` field, the `result` object, you will also get an additional `fetchStatus`property with the following options:
In addition to the `status` field and the `result` object, you will also get an additional `fetchStatus` property with the following options:

- `fetchStatus === 'fetching'` - The query is currently fetching.
- `fetchStatus === 'paused'` - The query wanted to fetch, but it is paused. Read more about this in the [Network Mode](../guides/network-mode) guide.
Expand Down
2 changes: 2 additions & 0 deletions docs/react/plugins/broadcastQueryClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ interface broadcastQueryClient {
/** This is the unique channel name that will be used
* to communicate between tabs and windows */
broadcastChannel?: string
/** Options for the BroadcastChannel API */
options?: BroadcastChannelOptions
}
```

Expand Down
3 changes: 1 addition & 2 deletions docs/svelte/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,8 @@ Svelte Query supports prefetching queries on the server. Using this setup below,
```ts
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'
import type { LayoutLoad } from './$types'

export const load: LayoutLoad = async () => {
export const load = async () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
Expand Down
4 changes: 2 additions & 2 deletions examples/vue/dependent-queries/src/Post.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export default defineComponent({
const { data: author } = useQuery(
['author', authorId],
() => fetchAuthor(authorId.value),
({ queryKey: [, id] }) => fetchAuthor(id),
{
enabled: computed(() => !!post.value?.userId),
enabled: computed(() => !!authorId.value),
},
)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@
"jest": "^27.5.1",
"jsonfile": "^6.1.0",
"luxon": "^2.3.2",
"nx": "16.5.2",
"nx-cloud": "16.1.0",
"nx": "16.7.4",
"nx-cloud": "16.3.0",
"prettier": "^2.6.2",
"prettier-plugin-svelte": "^2.9.0",
"react": "^18.2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-async-storage-persister/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-async-storage-persister",
"version": "4.33.0",
"version": "4.35.0",
"description": "A persister for asynchronous storages, to be used with TanStack/Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-broadcast-client-experimental/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-broadcast-client-experimental",
"version": "4.33.0",
"version": "4.35.0",
"description": "An experimental plugin to for broadcasting the state of your queryClient between browser tabs/windows",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
4 changes: 4 additions & 0 deletions packages/query-broadcast-client-experimental/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { BroadcastChannel } from 'broadcast-channel'
import type { BroadcastChannelOptions } from 'broadcast-channel'
import type { QueryClient } from '@tanstack/query-core'

interface BroadcastQueryClientOptions {
queryClient: QueryClient
broadcastChannel?: string
options?: BroadcastChannelOptions
}

export function broadcastQueryClient({
queryClient,
broadcastChannel = 'tanstack-query',
options,
}: BroadcastQueryClientOptions) {
let transaction = false
const tx = (cb: () => void) => {
Expand All @@ -19,6 +22,7 @@ export function broadcastQueryClient({

const channel = new BroadcastChannel(broadcastChannel, {
webWorkerSupport: false,
...options,
})

const queryCache = queryClient.getQueryCache()
Expand Down
2 changes: 1 addition & 1 deletion packages/query-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-core",
"version": "4.33.0",
"version": "4.35.0",
"description": "The framework agnostic core that powers TanStack Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions packages/query-core/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,8 @@ export class Query<
}
}

if (!Array.isArray(this.options.queryKey)) {
if (process.env.NODE_ENV !== 'production') {
if (process.env.NODE_ENV !== 'production') {
if (!Array.isArray(this.options.queryKey)) {
this.logger.error(
`As of v4, queryKey needs to be an Array. If you are using a string like 'repoData', please change it to an Array, e.g. ['repoData']`,
)
Expand Down
3 changes: 3 additions & 0 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export interface QueryOptions<
retryDelay?: RetryDelayValue<TError>
networkMode?: NetworkMode
cacheTime?: number
/**
* @deprecated This callback will be removed in the next major version. You can achieve the same functionality by passing a function to `structuralSharing` instead.
*/
isDataEqual?: (oldData: TData | undefined, newData: TData) => boolean
queryFn?: QueryFunction<TQueryFnData, TQueryKey>
queryHash?: string
Expand Down
2 changes: 1 addition & 1 deletion packages/query-persist-client-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-persist-client-core",
"version": "4.33.0",
"version": "4.35.0",
"description": "Set of utilities for interacting with persisters, which can save your queryClient for later use",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-sync-storage-persister/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-sync-storage-persister",
"version": "4.33.0",
"version": "4.35.0",
"description": "A persister for synchronous storages, to be used with TanStack/Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-query-devtools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/react-query-devtools",
"version": "4.33.0",
"version": "4.35.0",
"description": "Developer tools to interact with and visualize the TanStack/react-query cache",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-query-persist-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/react-query-persist-client",
"version": "4.33.0",
"version": "4.35.0",
"description": "React bindings to work with persisters in TanStack/react-query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-query/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/react-query",
"version": "4.33.0",
"version": "4.35.0",
"description": "Hooks for managing, caching and syncing asynchronous and remote data in React",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/solid-query/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/solid-query",
"version": "4.33.0",
"version": "4.35.0",
"description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte-query/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/svelte-query",
"version": "4.33.0",
"version": "4.35.0",
"description": "Primitives for managing, caching and syncing asynchronous and remote data in Svelte",
"author": "Lachlan Collins",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-query/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/vue-query",
"version": "4.34.0",
"version": "4.35.1",
"description": "Hooks for managing, caching and syncing asynchronous and remote data in Vue",
"author": "Damian Osipiuk",
"license": "MIT",
Expand Down
41 changes: 35 additions & 6 deletions packages/vue-query/src/__tests__/useQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ describe('useQuery', () => {
})

secondKeyRef.value = 'key8'
await flushPromises()

expect(query).toMatchObject({
status: { value: 'loading' },
data: { value: undefined },
Expand All @@ -172,9 +170,6 @@ describe('useQuery', () => {
})

enabled.value = true

await flushPromises()

expect(query).toMatchObject({
fetchStatus: { value: 'fetching' },
data: { value: undefined },
Expand All @@ -192,16 +187,18 @@ describe('useQuery', () => {

const enabled = computed(() => !!data.value)

const dependentQueryFn = jest.fn().mockImplementation(simpleFetcher)
const { fetchStatus, status } = useQuery(
['dependant2'],
simpleFetcher,
dependentQueryFn,
reactive({
enabled,
}),
)

expect(data.value).toStrictEqual(undefined)
expect(fetchStatus.value).toStrictEqual('idle')
expect(dependentQueryFn).not.toHaveBeenCalled()

await flushPromises()

Expand All @@ -212,6 +209,10 @@ describe('useQuery', () => {

expect(fetchStatus.value).toStrictEqual('idle')
expect(status.value).toStrictEqual('success')
expect(dependentQueryFn).toHaveBeenCalledTimes(1)
expect(dependentQueryFn).toHaveBeenCalledWith(
expect.objectContaining({ queryKey: ['dependant2'] }),
)
})

test('should stop listening to changes on onScopeDispose', async () => {
Expand All @@ -233,6 +234,34 @@ describe('useQuery', () => {
expect(status.value).toStrictEqual('loading')
})

test('should use the current value for the queryKey when refetch is called', async () => {
const fetchFn = jest.fn()
const keyRef = ref('key11')
const query = useQuery({
queryKey: ['key10', keyRef],
queryFn: fetchFn,
enabled: false,
})

expect(fetchFn).not.toHaveBeenCalled()
await query.refetch()
expect(fetchFn).toHaveBeenCalledTimes(1)
expect(fetchFn).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: ['key10', 'key11'],
}),
)

keyRef.value = 'key12'
await query.refetch()
expect(fetchFn).toHaveBeenCalledTimes(2)
expect(fetchFn).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: ['key10', 'key12'],
}),
)
})

describe('errorBoundary', () => {
test('should evaluate useErrorBoundary when query is expected to throw', async () => {
const boundaryFn = jest.fn()
Expand Down
28 changes: 25 additions & 3 deletions packages/vue-query/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ import type {
import type { Ref, UnwrapRef } from 'vue-demi'
import type { QueryClient } from './queryClient'

export type MaybeRef<T> = Ref<T> | T
type Primitive = string | number | boolean | bigint | symbol | undefined | null
type UnwrapLeaf =
| Primitive
| Function
| Date
| Error
| RegExp
| Map<any, any>
| WeakMap<any, any>
| Set<any>
| WeakSet<any>

export type MaybeRefDeep<T> = MaybeRef<
T extends Function
Expand All @@ -20,6 +30,18 @@ export type MaybeRefDeep<T> = MaybeRef<
: T
>

export type MaybeRef<T> = Ref<T> | T

export type DeepUnwrapRef<T> = T extends UnwrapLeaf
? T
: T extends Ref<infer U>
? DeepUnwrapRef<U>
: T extends {}
? {
[Property in keyof T]: DeepUnwrapRef<T[Property]>
}
: UnwrapRef<T>

export type WithQueryClientKey<T> = T & {
queryClientKey?: string
queryClient?: QueryClient
Expand All @@ -46,7 +68,7 @@ export type VueQueryObserverOptions<
TError,
TData,
TQueryData,
UnwrapRef<TQueryKey>
DeepUnwrapRef<TQueryKey>
>[Property]
: MaybeRef<
QueryObserverOptions<
Expand Down Expand Up @@ -80,7 +102,7 @@ export type VueInfiniteQueryObserverOptions<
TError,
TData,
TQueryData,
UnwrapRef<TQueryKey>
DeepUnwrapRef<TQueryKey>
>[Property]
: MaybeRef<
InfiniteQueryObserverOptions<
Expand Down
Loading

0 comments on commit 731bba6

Please sign in to comment.