Skip to content

Commit

Permalink
Merge pull request #4 from tannerlinsley/master
Browse files Browse the repository at this point in the history
update
  • Loading branch information
TkDodo committed Apr 23, 2021
2 parents e29ae76 + 64dec9e commit 37a3118
Show file tree
Hide file tree
Showing 17 changed files with 80 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Expand Up @@ -29,7 +29,7 @@
],
"no-shadow": "error",
"import/no-cycle": "error",
"import/no-unresolved": "error",
"import/no-unresolved": ["error", { "ignore": ["react-query"] }],
"import/no-unused-modules": ["off", { "unusedExports": true }],
"no-redeclare": "off"
}
Expand Down
4 changes: 3 additions & 1 deletion docs/src/pages/guides/migrating-to-react-query-3.md
Expand Up @@ -48,6 +48,8 @@ const queryClient = new QueryClient()

Default options for queries and mutations can now be specified in `QueryClient`:

**Notice that it's now defaultOptions instead of defaultConfig**

```js
const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -147,7 +149,7 @@ They were previously added as the last query key parameter in your query functio
useInfiniteQuery(['posts'], (_key, pageParam = 0) => fetchPosts(pageParam))

// New
useInfiniteQuery(['posts'], ({ pageParam = 0 }) => fetchPost(pageParam))
useInfiniteQuery(['posts'], ({ pageParam = 0 }) => fetchPosts(pageParam))
```

### usePaginatedQuery() has been deprecated in favor of the `keepPreviousData` option
Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/guides/mutations.md
Expand Up @@ -53,10 +53,10 @@ In the example above, you also saw that you can pass variables to your mutations

Even with just variables, mutations aren't all that special, but when used with the `onSuccess` option, the [Query Client's `invalidateQueries` method](../reference/QueryClient#queryclientinvalidatequeries) and the [Query Client's `setQueryData` method](../reference/QueryClient#queryclientsetquerydata), mutations become a very powerful tool.

> IMPORTANT: The `mutate` function is an asynchronous function, which means you cannot use it directly in an event callback. If you need to access the event in `onSubmit` you need to wrap `mutate` in another function. This is due to [React event pooling](https://reactjs.org/docs/events.html#event-pooling).
> IMPORTANT: The `mutate` function is an asynchronous function, which means you cannot use it directly in an event callback in **React 16 and earlier**. If you need to access the event in `onSubmit` you need to wrap `mutate` in another function. This is due to [React event pooling](https://reactjs.org/docs/legacy-event-pooling.html).
```js
// This will not work
// This will not work in React 16 and earlier
const CreateTodo = () => {
const mutation = useMutation(event => {
event.preventDefault()
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/overview.md
Expand Up @@ -20,7 +20,7 @@ Once you grasp the nature of server state in your application, **even more chall

- Caching... (possibly the hardest thing to do in programming)
- Deduping multiple requests for the same data into a single request
- Updating out of date data in the background
- Updating "out of date" data in the background
- Knowing when data is "out of date"
- Reflecting updates to data as quickly as possible
- Performance optimizations like pagination and lazy loading data
Expand Down
5 changes: 5 additions & 0 deletions docs/src/pages/reference/useQuery.md
Expand Up @@ -89,6 +89,8 @@ const result = useQuery({
- A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff.
- A function like `attempt => attempt * 1000` applies linear backoff.
- `staleTime: number | Infinity`
- Optional
- Defaults to `0`
- The time in milliseconds after data is considered stale. This value only applies to the hook it is defined on.
- If set to `Infinity`, the data will never be considered stale
- `cacheTime: number | Infinity`
Expand Down Expand Up @@ -168,6 +170,9 @@ const result = useQuery({
- Optional
- Defaults to `true`
- If set to `false`, structural sharing between query results will be disabled.
- `useErrorBoundary: boolean`
- Defaults to the global query config's `useErrorBoundary` value, which is false
- Set this to true if you want errors to be thrown in the render phase and propagated to the nearest error boundary
**Returns**
Expand Down
3 changes: 2 additions & 1 deletion rollup.config.js
Expand Up @@ -7,11 +7,12 @@ import commonJS from 'rollup-plugin-commonjs'
import visualizer from 'rollup-plugin-visualizer'
import replace from '@rollup/plugin-replace'

const external = ['react', 'react-dom']
const external = ['react', 'react-dom', 'react-query']

const globals = {
react: 'React',
'react-dom': 'ReactDOM',
'react-query': 'ReactQuery',
}

const inputSrcs = [
Expand Down
15 changes: 15 additions & 0 deletions src/core/infiniteQueryObserver.ts
Expand Up @@ -75,6 +75,21 @@ export class InfiniteQueryObserver<
})
}

getOptimisticResult(
options: InfiniteQueryObserverOptions<
TQueryFnData,
TError,
TData,
TQueryData
>
): InfiniteQueryObserverResult<TData, TError> {
options.behavior = infiniteQueryBehavior()
return super.getOptimisticResult(options) as InfiniteQueryObserverResult<
TData,
TError
>
}

fetchNextPage(
options?: FetchNextPageOptions
): Promise<InfiniteQueryObserverResult<TData, TError>> {
Expand Down
8 changes: 3 additions & 5 deletions src/core/query.ts
@@ -1,6 +1,5 @@
import {
Updater,
ensureArray,
functionalUpdate,
isValidTimeout,
noop,
Expand Down Expand Up @@ -378,9 +377,8 @@ export class Query<
}

// Create query function context
const queryKey = ensureArray(this.queryKey)
const queryFnContext: QueryFunctionContext<unknown[]> = {
queryKey,
const queryFnContext: QueryFunctionContext<TQueryKey> = {
queryKey: this.queryKey,
pageParam: undefined,
}

Expand All @@ -394,7 +392,7 @@ export class Query<
const context: FetchContext<TQueryFnData, TError, TData, any> = {
fetchOptions,
options: this.options,
queryKey,
queryKey: this.queryKey,
state: this.state,
fetchFn,
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/types.ts
Expand Up @@ -59,7 +59,7 @@ export interface QueryOptions<
retryDelay?: RetryDelayValue<TError>
cacheTime?: number
isDataEqual?: (oldData: TData | undefined, newData: TData) => boolean
queryFn?: QueryFunction<TQueryFnData>
queryFn?: QueryFunction<TQueryFnData, TQueryKey>
queryHash?: string
queryKey?: TQueryKey
queryKeyHashFn?: QueryKeyHashFunction<TQueryKey>
Expand Down
7 changes: 4 additions & 3 deletions src/devtools/devtools.tsx
@@ -1,10 +1,11 @@
// @ts-nocheck

import React from 'react'

import { useQueryClient } from 'react-query'
import { matchSorter } from 'match-sorter'
import { useQueryClient } from '../react'
import useLocalStorage from './useLocalStorage'
import { useSafeState, isStale } from './utils'
import { useSafeState } from './utils'

import {
Panel,
Expand Down Expand Up @@ -305,7 +306,7 @@ export function ReactQueryDevtools({
}

const getStatusRank = q =>
q.state.isFetching ? 0 : !q.observers.length ? 3 : isStale(q) ? 2 : 1
q.state.isFetching ? 0 : !q.observers.length ? 3 : q.isStale() ? 2 : 1

const sortFns = {
'Status > Last Updated': (a, b) =>
Expand Down
10 changes: 2 additions & 8 deletions src/devtools/utils.ts
Expand Up @@ -7,16 +7,10 @@ import useMediaQuery from './useMediaQuery'

export const isServer = typeof window === 'undefined'

export function isStale(query) {
return typeof query.isStale === 'function'
? query.isStale()
: query.state.isStale
}

export function getQueryStatusColor(query, theme) {
return query.state.isFetching
? theme.active
: isStale(query)
: query.isStale()
? theme.warning
: !query.observers.length
? theme.gray
Expand All @@ -28,7 +22,7 @@ export function getQueryStatusLabel(query) {
? 'fetching'
: !query.observers.length
? 'inactive'
: isStale(query)
: query.isStale()
? 'stale'
: 'fresh'
}
Expand Down
2 changes: 1 addition & 1 deletion src/hydration/react.tsx
@@ -1,6 +1,6 @@
import React from 'react'

import { useQueryClient } from '../react'
import { useQueryClient } from 'react-query'
import { hydrate, HydrateOptions } from './hydration'

export function useHydrate(state: unknown, options?: HydrateOptions) {
Expand Down
20 changes: 15 additions & 5 deletions src/react/tests/suspense.test.tsx
Expand Up @@ -72,19 +72,20 @@ describe("useQuery's in Suspense mode", () => {
const states: UseInfiniteQueryResult<number>[] = []

function Page() {
const [multiplier, setMultiplier] = React.useState(1)
const state = useInfiniteQuery(
key,
({ pageParam = 0 }) => Number(pageParam),
`${key}_${multiplier}`,
({ pageParam = 1 }) => Number(pageParam * multiplier),
{
suspense: true,
getNextPageParam: lastPage => lastPage + 1,
}
)
states.push(state)
return null
return <button onClick={() => setMultiplier(2)}>next</button>
}

renderWithClient(
const rendered = renderWithClient(
queryClient,
<React.Suspense fallback="loading">
<Page />
Expand All @@ -95,7 +96,16 @@ describe("useQuery's in Suspense mode", () => {

expect(states.length).toBe(1)
expect(states[0]).toMatchObject({
data: { pages: [0], pageParams: [undefined] },
data: { pages: [1], pageParams: [undefined] },
status: 'success',
})

fireEvent.click(rendered.getByText('next'))
await sleep(10)

expect(states.length).toBe(3)
expect(states[2]).toMatchObject({
data: { pages: [2], pageParams: [undefined] },
status: 'success',
})
})
Expand Down
15 changes: 15 additions & 0 deletions src/react/tests/useQuery.test.tsx
Expand Up @@ -16,6 +16,7 @@ import {
QueryClient,
UseQueryResult,
QueryCache,
QueryFunction,
QueryFunctionContext,
} from '../..'

Expand Down Expand Up @@ -74,6 +75,20 @@ describe('useQuery', () => {
})
expectType<string | undefined>(fromGenericOptionsQueryFn.data)
expectType<unknown>(fromGenericOptionsQueryFn.error)

type MyData = number
type MyQueryKey = readonly ['my-data', number]

const getMyData: QueryFunction<MyData, MyQueryKey> = async ({
queryKey: [, n],
}) => {
return n + 42
}

useQuery({
queryKey: ['my-data', 100],
queryFn: getMyData,
})
}
})

Expand Down
3 changes: 2 additions & 1 deletion src/react/types.ts
Expand Up @@ -4,6 +4,7 @@ import {
InfiniteQueryObserverResult,
MutateOptions,
MutationStatus,
MutationKey,
QueryObserverOptions,
QueryObserverResult,
QueryKey,
Expand Down Expand Up @@ -74,7 +75,7 @@ export interface UseMutationOptions<
TVariables = void,
TContext = unknown
> {
mutationKey?: string | unknown[]
mutationKey?: MutationKey
onMutate?: (variables: TVariables) => Promise<TContext> | Promise<undefined> | TContext | undefined
onSuccess?: (
data: TData,
Expand Down
5 changes: 4 additions & 1 deletion tsconfig.json
Expand Up @@ -13,7 +13,10 @@
"noUnusedParameters": true,
"skipLibCheck": true,
"strict": true,
"types": ["jest"]
"types": ["jest"],
"paths": {
"react-query": ["./src/index.ts"]
}
},
"include": ["./src"]
}
5 changes: 4 additions & 1 deletion tsconfig.types.json
Expand Up @@ -4,7 +4,10 @@
"declaration": true,
"declarationDir": "./types",
"emitDeclarationOnly": true,
"noEmit": false
"noEmit": false,
"paths": {
"react-query": ["./src/index.ts"]
}
},
"files": [
"./src/index.ts",
Expand Down

0 comments on commit 37a3118

Please sign in to comment.