Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isFetching is always true when useQueries have duplicate query #8224

Closed
tychenjiajun opened this issue Oct 26, 2024 · 4 comments · Fixed by #8246
Closed

isFetching is always true when useQueries have duplicate query #8224

tychenjiajun opened this issue Oct 26, 2024 · 4 comments · Fixed by #8246

Comments

@tychenjiajun
Copy link

Describe the bug

isFetching, isLoading is always true when useQueries have duplicate query

  const { data, isFetching, isLoading, isFetched } = useQueries({
    queries: [query, query, query2],
    // queries: [query],
    combine: useCallback((result) => {
      return {
        data: result[0].data,

        isFetching: result.some((r) => r.isFetching),
        isLoading: result.some((r) => r.isLoading),
        isFetched: result.every((r) => r.isFetched),
      };
    }, []),
  });

Your minimal, reproducible example

https://codesandbox.io/p/sandbox/elegant-kapitsa-c3c357

Steps to reproduce

import "./styles.css";
import { useCallback } from "react";

import {
  useQueries,
  queryOptions,
  QueryClient,
  QueryClientProvider,
} from "@tanstack/react-query";

const query = queryOptions({
  queryKey: ["users"],
  async queryFn() {
    const result = await fetch("https://jsonplaceholder.typicode.com/users");
    return await result.json();
  },
});

const query2 = queryOptions({
  queryKey: ["posts"],
  async queryFn() {
    const result = await fetch("https://jsonplaceholder.typicode.com/posts");
    return await result.json();
  },
});

const client = new QueryClient();

const Example = () => {
  const { data, isFetching, isLoading, isFetched } = useQueries({
    queries: [query, query, query2],
    // queries: [query],
    combine: useCallback((result) => {
      return {
        data: result[0].data,

        isFetching: result.some((r) => r.isFetching),
        isLoading: result.some((r) => r.isLoading),
        isFetched: result.every((r) => r.isFetched),
      };
    }, []),
  });

  return (
    <div>
      {isFetching && "isFetching"}
      {isLoading && "isLoading"}
      {isFetched && "isFetched"}
      {data?.length}
    </div>
  );
};

export default function App() {
  return (
    <QueryClientProvider client={client}>
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <Example />
      </div>
    </QueryClientProvider>
  );
}

Expected behavior

expect isFetching and isLoading to be false

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

macOs 15.0.1

Tanstack Query adapter

react-query

TanStack Query version

5.59.16

TypeScript version

No response

Additional context

No response

@tychenjiajun
Copy link
Author

tychenjiajun commented Oct 26, 2024

Maybe duplicated #4303 #4187

It might be better if we have runtime warning in development

@olivierbeaulieu
Copy link

olivierbeaulieu commented Dec 2, 2024

Would you mind explaining what the cause is? It sounds somewhat different from #4187, where placeholderData causes the issue?

The codesandbox reproduction of this issue has no placeholderData involved, so I'm a bit puzzled by what the cause is?

@TkDodo
Copy link
Collaborator

TkDodo commented Dec 6, 2024

we don’t support same keys in the array because a) it doesn’t achieve anything - why would you do that, it’s just redundant and b) we use the keys to keep track of where a query is in the array to support detection of changed keys, and it just doesn’t work if there are items that have the same key hash.

@jbblanchet
Copy link

@TkDodo Sorry to comment on a closed issue, but you were asking (perhaps rhetorically) "why would you do that, it’s just redundant", and I believe I have a use case that could answer your question. We need to support an arbitrary number of columns, each representing an object that needs to be loaded. We still need to run all these queries in a single component, because the ordering of the rows might depend on multiple columns. And lastly, adding the same column twice is in our case a valid use case.

Because of how hooks work, I need to combine all of these queries in a single useQueries. And because some of them have the same key (they're actually the same object, and I don't want to run the query twice), then my whole screen stops working, because it keeps the isFetching state.

I understand this is an edge case, and I'm built my own helper to combine and re-spread the queries and their results in the right way. I just wanted to document this use case if anyone ever ask why would someone do that in the future.

Oh and I also believe that your documentation is out of date. In the useQueries documentation, the warning simply says:

Having the same query key more than once in the array of query objects may cause some data to be shared between queries. To avoid this, consider de-duplicating the queries and map the results back to the desired structure.

I believe this should be re-worded to make clear that having duplicate keys is NOT supported at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants