Skip to content

Commit

Permalink
fix: mutate requires arguments if middleware is used
Browse files Browse the repository at this point in the history
  • Loading branch information
liaoxuan committed Feb 18, 2024
1 parent 85a9986 commit 35389af
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 26 deletions.
60 changes: 50 additions & 10 deletions README-zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
- [createMutation](#createmutation)
- [router](#router)
- [中间件](#中间件)
- [TypeScript](#typescript)
- [类型推导](#类型推导)
- [常见问题](#常见问题)
- [迁移](#迁移)
Expand Down Expand Up @@ -83,12 +84,12 @@ $ yarn add react-query-kit
import { QueryClient, dehydrate } from '@tanstack/react-query'
import { createQuery } from 'react-query-kit'

type Response = { title: string; content: string }
type Data = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery({
queryKey: ['posts'],
fetcher: (variables: Variables): Promise<Response> => {
fetcher: (variables: Variables): Promise<Data> => {
return fetch(`/posts/${variables.id}`).then(res => res.json())
},
// 你还可以通过中间件来定制这个 hook 的行为
Expand Down Expand Up @@ -140,7 +141,7 @@ const queries = useQueries({
})

// getQueryData
queryClient.getQueryData(usePost.getKey(variables)) // Response
queryClient.getQueryData(usePost.getKey(variables)) // Data

// setQueryData
queryClient.setQueryData(usePost.getKey(variables), {...})
Expand Down Expand Up @@ -175,12 +176,12 @@ Expose Methods
import { QueryClient, dehydrate } from '@tanstack/react-query'
import { createInfiniteQuery } from 'react-query-kit'

type Response = { projects: { id: string; name: string }[]; nextCursor: number }
type Data = { projects: { id: string; name: string }[]; nextCursor: number }
type Variables = { active: boolean }

const useProjects = createInfiniteQuery({
queryKey: ['projects'],
fetcher: (variables: Variables, { pageParam }): Promise<Response> => {
fetcher: (variables: Variables, { pageParam }): Promise<Data> => {
return fetch(
`/projects?cursor=${pageParam}?active=${variables.active}`
).then(res => res.json())
Expand Down Expand Up @@ -478,7 +479,7 @@ Expose Methods
import { QueryClient } from '@tanstack/react-query'
import { Middleware, MutationHook, QueryHook, getKey } from 'react-query-kit'

const logger: Middleware<QueryHook<Response, Variables>> = useQueryNext => {
const logger: Middleware<QueryHook<Data, Variables>> = useQueryNext => {
return options => {
const log = useLogger()
const fetcher = (variables, context) => {
Expand All @@ -493,7 +494,7 @@ const logger: Middleware<QueryHook<Response, Variables>> = useQueryNext => {
}
}

const useUser = createQuery<Response, Variables>({
const useUser = createQuery<Data, Variables>({
use: [logger],
})

Expand Down Expand Up @@ -593,17 +594,56 @@ const useSomething = createQuery({
useSomething({...}, anotherQueryClient)
```

## TypeScript

默认情况下,ReactQueryKit 还会从 `fetcher` 推断 `data``variables` 的类型,因此您可以自动获得首选类型。

```ts
type Data = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery({
queryKey: ['posts'],
fetcher: (variables: Variables): Promise<Data> => {
return fetch(`/posts/${variables}`).then(res => res.json())
},
})

// `data` 将被推断为 `Data | undefined`.
// `variables` 将被推断为 `Variables`.
const { data } = usePost({ variables: 1 })
```

您还可以显式指定 `fetcher` 参数和返回的类型。

```ts
type Data = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery<Data, Variables, Error>({
queryKey: ['posts'],
fetcher: variables => {
return fetch(`/posts/${variables}`).then(res => res.json())
},
})

// `data` 将被推断为 `Data | undefined`.
// `error` 将被推断为 `Error | null`
// `variables` 将被推断为 `Variables`.
const { data, error } = usePost({ variables: 1 })
```

## 类型推导

您可以使用 `inferData``inferVariables` 提取任何自定义 hook 的 TypeScript 类型

```ts
import { inferData, inferFnData, inferError, inferVariables, inferOptions } from 'react-query-kit'

const useProjects = createInfiniteQuery<Response, Variables>(...)
const useProjects = createInfiniteQuery<Data, Variables>(...)

inferData<typeof useProjects> // InfiniteData<Response>
inferFnData<typeof useProjects> // Response
inferData<typeof useProjects> // InfiniteData<Data>
inferFnData<typeof useProjects> // Data
inferVariables<typeof useProjects> // Variables
inferError<typeof useProjects> // Error
inferOptions<typeof useProjects> // InfiniteQueryHookOptions<...>
Expand Down
60 changes: 50 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ English | [简体中文](./README-zh_CN.md)
- [createMutation](#createmutation)
- [router](#router)
- [Middleware](#middleware)
- [TypeScript](#typescript)
- [Type inference](#type-inference)
- [FAQ](#faq)
- [Migration](#migration)
Expand Down Expand Up @@ -86,12 +87,12 @@ If you still on React Query Kit v2? Check out the v2 docs here: https://github.c
import { QueryClient, dehydrate } from '@tanstack/react-query'
import { createQuery } from 'react-query-kit'

type Response = { title: string; content: string }
type Data = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery({
queryKey: ['posts'],
fetcher: (variables: Variables): Promise<Response> => {
fetcher: (variables: Variables): Promise<Data> => {
return fetch(`/posts/${variables.id}`).then(res => res.json())
},
// u can also pass middleware to cutomize this hook's behavior
Expand Down Expand Up @@ -142,7 +143,7 @@ const queries = useQueries({
})

// getQueryData
queryClient.getQueryData(usePost.getKey(variables)) // Response
queryClient.getQueryData(usePost.getKey(variables)) // Data

// setQueryData
queryClient.setQueryData(usePost.getKey(variables), {...})
Expand Down Expand Up @@ -177,12 +178,12 @@ Expose Methods
import { QueryClient, dehydrate } from '@tanstack/react-query'
import { createInfiniteQuery } from 'react-query-kit'

type Response = { projects: { id: string; name: string }[]; nextCursor: number }
type Data = { projects: { id: string; name: string }[]; nextCursor: number }
type Variables = { active: boolean }

const useProjects = createInfiniteQuery({
queryKey: ['projects'],
fetcher: (variables: Variables, { pageParam }): Promise<Response> => {
fetcher: (variables: Variables, { pageParam }): Promise<Data> => {
return fetch(
`/projects?cursor=${pageParam}?active=${variables.active}`
).then(res => res.json())
Expand Down Expand Up @@ -478,7 +479,7 @@ Middleware receive the hook and can execute logic before and after running it. I
import { QueryClient } from '@tanstack/react-query'
import { Middleware, MutationHook, QueryHook, getKey } from 'react-query-kit'

const logger: Middleware<QueryHook<Response, Variables>> = useQueryNext => {
const logger: Middleware<QueryHook<Data, Variables>> = useQueryNext => {
return options => {
const log = useLogger()
const fetcher = (variables, context) => {
Expand All @@ -493,7 +494,7 @@ const logger: Middleware<QueryHook<Response, Variables>> = useQueryNext => {
}
}

const useUser = createQuery<Response, Variables>({
const useUser = createQuery<Data, Variables>({
use: [logger],
})

Expand Down Expand Up @@ -593,17 +594,56 @@ const useSomething = createQuery({
useSomething({...}, anotherQueryClient)
```

## TypeScript

By default, ReactQueryKit will also infer the types of `data` and `variables` from `fetcher`, so you can have the preferred types automatically.

```ts
type Data = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery({
queryKey: ['posts'],
fetcher: (variables: Variables): Promise<Data> => {
return fetch(`/posts/${variables}`).then(res => res.json())
},
})

// `data` will be inferred as `Data | undefined`.
// `variables` will be inferred as `Variables`.
const { data } = usePost({ variables: 1 })
```

You can also explicitly specify the types for `fetcher`‘s `variables` and `data`.

```ts
type Data = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery<Data, Variables, Error>({
queryKey: ['posts'],
fetcher: variables => {
return fetch(`/posts/${variables}`).then(res => res.json())
},
})

// `data` will be inferred as `Data | undefined`.
// `error` will be inferred as `Error | null`
// `variables` will be inferred as `Variables`.
const { data, error } = usePost({ variables: 1 })
```

## Type inference

You can extract the TypeScript type of any custom hook with `inferData` or `inferVariables`

```ts
import { inferData, inferFnData, inferError, inferVariables, inferOptions } from 'react-query-kit'

const useProjects = createInfiniteQuery<Response, Variables, Error>(...)
const useProjects = createInfiniteQuery<Data, Variables, Error>(...)

inferData<typeof useProjects> // InfiniteData<Response>
inferFnData<typeof useProjects> // Response
inferData<typeof useProjects> // InfiniteData<Data>
inferFnData<typeof useProjects> // Data
inferVariables<typeof useProjects> // Variables
inferError<typeof useProjects> // Error
inferOptions<typeof useProjects> // InfiniteQueryHookOptions<...>
Expand Down
12 changes: 6 additions & 6 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,15 +445,15 @@ export interface CreateMutationOptions<
TError = CompatibleError,
TContext = unknown
> extends UseMutationOptions<TData, TError, TVariables, TContext> {
use?: Middleware<MutationHook<TData, TError, TVariables>>[]
use?: Middleware<MutationHook<TData, TVariables, TError>>[]
}

export interface MutationHookOptions<TData, TError, TVariables, TContext>
extends Omit<
UseMutationOptions<TData, TError, TVariables, TContext>,
UseMutationOptions<TData, TVariables, TError, TContext>,
'mutationFn' | 'mutationKey'
> {
use?: Middleware<MutationHook<TData, TError, TVariables>>[]
use?: Middleware<MutationHook<TData, TVariables, TError>>[]
}

export type MutationHookResult<
Expand All @@ -466,7 +466,7 @@ export type MutationHookResult<
export interface ExposeMutationMethods<
TData = unknown,
TVariables = void,
TError = unknown,
TError = CompatibleError,
TDefaultContext = unknown
> {
getKey: () => MutationKey | undefined
Expand All @@ -482,7 +482,7 @@ export interface ExposeMutationMethods<
export interface MutationHook<
TData = unknown,
TVariables = void,
TError = unknown,
TError = CompatibleError,
TDefaultContext = unknown
> extends ExposeMutationMethods<TData, TVariables, TError, TDefaultContext> {
<TContext = TDefaultContext>(
Expand Down Expand Up @@ -593,7 +593,7 @@ export type inferCreateOptions<T> = T extends QueryHook<
infer TError,
infer TContext
>
? CreateMutationOptions<TFnData, TError, TVariables, TContext>
? CreateMutationOptions<TFnData, TVariables, TError, TContext>
: never

// router
Expand Down

0 comments on commit 35389af

Please sign in to comment.