HuolalaTech/react-query-kit

Suppress `Duplicated primaryKey` console warning

Closed this issue ยท 12 comments

snelsi commented

v2.0.4 introduced automatic Duplicated primaryKey warning.

I call createQuery and createSuspenseQuery in the same file with the same options to create 2 versions of the same hook.
It allows me to have both useQuery and useSuspenseQuery versions too choose from, depending on the usage context.

Since they use the same queryFn, call the same endpoint with the same params, and useSuspenseQuery is kinda just a syntactic sugar for useQuery({ suspense: true }), I don't think they need to have different primaryKey.

After updating too v2.0.4 I started too see a lot off Duplicated primaryKey warnings.
I assume they are false-positive for my setup?

Is it possible to suppress this console warning? Perhaps, by passing some new prop to options.

Also, I see Duplicated primaryKey warning a lot during a Next.js fast recompile when working localy. But it's probably unrelated.

I don't think it's a good pattern to create two queries with the same primary key, which means this won't be a singleton.

const useUser = createSuspenseQuery()

// For rare cases you can use getOptions to subscribe or do something other
useQuery({
 ...useUser.getOptions(),
enabled: false
})
snelsi commented

tRPC uses the same pattern. There's nothing wrong with it.
When creating query procedures, it provides you both with useQuery and useSuspenseQuery.

tRPC can organize this in a variable. But ReactQueryKit is not.
I am still not suggest to implement like that. But I can do a workaround to you.

After a lot of think, I wanna remove createSuspenseQuery and createSuspenseInfiniteQuery and use option suspense instead. And I know it is a big break change, but I think it will be worth.

It will also provide the best ts experience if you pass the option suspense: true. Now you can use yarn add react-query-kit@beta to experience it.

You can see the change of type of data from the belown example.

type Response = { title: string; content: string }

const usePost = createQuery<Response>({
  primaryKey: '/posts',
  queryFn: ({ queryKey: [primaryKey] }) => {
    return fetch(`${primaryKey}/1`).then(res => res.json())
  }
})

function App() {
  const { data } = usePost({
    initialData: { title: 'string', content: 'string' },
  })
 console.log(data) // Response

  const { data: data1 } = usePost({
    variables: { id: 1 },
  })
  console.log(data) // Response | undefined

  const { data: data2 } = usePost({ suspense: true })
  console.log(data) // Response
}
snelsi commented

IMHO, that's too radical solution for a simple console warning... ๐Ÿ˜…

useSuspenseQuery is an official hook included in Tanstack Query v5:

https://tanstack.com/query/v5/docs/react/community/suspensive-react-query#usesuspensequery-is-official-api-now-from-v5

image

Why introduce a mismatch in APIs? ๐Ÿค”

Also, if you managed to fix Typescript type definition for suspense: true, it might be worth opening a PR with those changes to @tanstack/query repo

It is not just a console warning., because it is too annoying to change plain query to suspense query and vice versa. Think of that if u pass some middleware in a custom query hook.

first scene

const useUser = createQuery({
// ...
use: [m1, m2, m3]
})

And it will miss these middleware if you via getOptions get the options to useSuspenseQuery

useSuspenseQuery(useUser.getOptions())

second scene

If you want to get two types of queries, then you must call createQuery and createSuspenseQuery to achieve it. I think this is very inelegant.

const useUser = createQuery({
primaryKey: "user'
})

const useSuspenseUser = createSuspenseQuery({
primaryKey: "user'
})

Finnally this is just a beta version, I will not include this featrue in release version unless you guys buy this idea

TkDodo commented

FYI, from a pure react-query perspective, we've moved away from the suspense:boolean flag in the public api. If you rely on this, it might not work in the future.

The reason is that suspense is not just a flag you can turn off or on - it's an architectural pattern. It changes how you need to structure components and how / where you have to do prefetching. Suspense also runs on the server with next13 app directory, normal queries don't. We might also integrate with a suspense-cache from react in the future (if that becomes a real thing), all of which led us to use a separate hook for suspense.

Also, the API is different. There is no placeholderData for suspense because it can never be shown. There is no keepPreviousData because with suspense, you want transitions.

I call createQuery and createSuspenseQuery in the same file with the same options to create 2 versions of the same hook.

I don't know much about react-query-kit, but in react-query v5, you'd use the queryOptions api for that:

const todoOptions = queryOptions({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 5000,
})

usage:

useQuery(todoOptions)
useSuspenseQuery(todoOptions)
queryClient.prefetchQuery(todoOptions)
const data = queryClient.getQueryData(todoOptions.queryKey)
// โฌ†๏ธ data returned here is typed to whatever fetchTodos returns!

@TkDodo Thank you for explaining this. This idea will be abandoned.

In addition. I found a bug with "queryOptions". Hopes to fix it.

type BizError = Error

const todoOptions = queryOptions<string, BizError>({
  queryKey: [`todo`],
  queryFn: () => 'dsa',
})

// this is will not work if u manualy set `BizError` to todoOptions
useQueries({
  queries: [todoOptions],
})

Seems there need to infer TError to fixed this bug. https://github.com/TanStack/query/blob/3e1f3ce412af007066efbc41678d2e72c9e5d325/packages/react-query/src/useQueries.ts#L68

TkDodo commented

Seems there need to infer TError to fixed this bug.

the useQueries types are a mystery to me ๐Ÿ˜… . If you can, please provide a fix for this. Apart from that, my suggestion is to never provide generics via <> but to infer them.

Errors cannot be inferred, but that's for a reason as there is no guarantee that you'll always get a BizError. You'll get a "normal" Error if something goes wrong in the select function for example. There's no way to enforce that statically, and the recommended way is to keep things typed to Error and use type-narrowing at runtime.

However, if you don't want that, you can provide a global type for all Errors via module augmentation in v5:

https://tanstack.com/query/v5/docs/react/typescript#registering-a-global-error

@snelsi Already remove Duplicated primaryKey console warning in v2.0.6