T
TanStack13mo ago
continuing-cyan

Help with no stale/inactive data, on refetch (breaks the site)

hey everyone, I've been a huge fan of react-query, and read many of tkdodo's blogs (huge inspiration). I was trying to implement the same for a production nextjs search application, but I faced an error. I hope this is a good place to discuss The problem is when I run a fetch, and try changing my facets (filters) to search again, react-query does the fetch and stores it, and if changed it turns inactive but if I go back to the same query combination within the stale time, it doesn't fetch and the website. has no content to show. so I have 2 queries running, one for facets and the other for the main search paginated query, both are interdependent so i have two different queries, one with the tag pagination other with facet with all variable deps. my query factories are
export const paginationQueryFactory = {
pagination: (params: SearchParamProps) =>
[
'pagination',
...params
] as const,
searchForFacets: (q: string) => ['searchForFacets', q] as const,
facets: (...facets: Array<string[] | undefined>) =>
['facets', facets] as const,
};


const usePaginatedQuery = ({
searchParams,
}: {
searchParams: SearchParamProps;
}) => {
const queryWithFilters = useQuery({
queryKey: paginationQueryFactory.pagination(searchParams),
queryFn: async () =>
fetchSearchData(
//fetcher
),
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});
return { queryWithFilters };
};
export const paginationQueryFactory = {
pagination: (params: SearchParamProps) =>
[
'pagination',
...params
] as const,
searchForFacets: (q: string) => ['searchForFacets', q] as const,
facets: (...facets: Array<string[] | undefined>) =>
['facets', facets] as const,
};


const usePaginatedQuery = ({
searchParams,
}: {
searchParams: SearchParamProps;
}) => {
const queryWithFilters = useQuery({
queryKey: paginationQueryFactory.pagination(searchParams),
queryFn: async () =>
fetchSearchData(
//fetcher
),
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});
return { queryWithFilters };
};
const useFacets = ({ searchParams }: { searchParams: SearchParamProps }) => {
const facets = [
...searchParams
];

const facetQuery = useQuery({
queryKey: QueryKeyFactory.facets(...facets),
queryFn: () => fetchFacets(searchParams),
refetchOnWindowFocus: false,
});

return facetQuery;
};
const useFacets = ({ searchParams }: { searchParams: SearchParamProps }) => {
const facets = [
...searchParams
];

const facetQuery = useQuery({
queryKey: QueryKeyFactory.facets(...facets),
queryFn: () => fetchFacets(searchParams),
refetchOnWindowFocus: false,
});

return facetQuery;
};
and then passing things through via a wrapper
6 Replies
fair-rose
fair-rose13mo ago
but if I go back to the same query combination within the stale time, it doesn't fetch and the website. has no content to show.
not fetching is expected, as it should just return cached data. Not seeing any content is obviously not expected, but I can't tell much without seeing a minimal codesandbox or stackblitz reproduction please
continuing-cyan
continuing-cyanOP13mo ago
thank you so much for replying, I was not exactly sure of what led to the error. And since the implementation is chained on a lot of factors it would be tough to reproduce. Can I give a quick video of what happened before I attempt to create a sandbox, please? and no i this was not due to suspense,
page.tsx

const page = ({ searchParams }: { searchParams: SearchParamProps }) => {
return (
<Search
searchParams={{ ...searchParams, page: searchParams.page || 1 }}
/>
);
};
page.tsx

const page = ({ searchParams }: { searchParams: SearchParamProps }) => {
return (
<Search
searchParams={{ ...searchParams, page: searchParams.page || 1 }}
/>
);
};
my current wrapper
import { ReactElement } from 'react';
import {
InfiniteData,
UseInfiniteQueryResult,
UseQueryResult,
} from '@tanstack/react-query';

/**
* @name WatchServiceQueryWrapper
* @description higher order wrapper for components that are consuming useQueries.
* @returns JSX.Element
*/

export type SearchQueryWrapperType<
SData extends 'normal' | 'infinite',
TData,
UData extends SData extends 'normal'
? UseQueryResult<TData, Error>
: UseInfiniteQueryResult<InfiniteData<TData, unknown>, Error>
> = {
type: SData;
query: UData;
children: (
_props: Extract<UData, { isSuccess: true }>['data']
) => ReactElement;
fallbackLoader?: ReactElement;
fallbackError?: (
_props: Extract<UData, { isError: true }>['error']
) => ReactElement;
loaderOnRefetch?: boolean;
};

const SearchQueryWrapper = <
SData extends 'normal' | 'infinite',
TData,
UData extends SData extends 'normal'
? UseQueryResult<TData, Error>
: UseInfiniteQueryResult<InfiniteData<TData, unknown>, Error>
>({
query,
children,
fallbackLoader,
fallbackError,
loaderOnRefetch,
}: SearchQueryWrapperType<SData, TData, UData>) => {
// return loading
if (loaderOnRefetch ? query.isFetching : query.isLoading) {
return fallbackLoader || <p>loading...</p>;
}

// return error
if (!query.isSuccess) {
const error = query.isError
? query.error
: new Error('Something went wrong');
return fallbackError?.(error) || <p>{error.message}</p>;
}

// return child
return children(query.data);
};

export default SearchQueryWrapper;
import { ReactElement } from 'react';
import {
InfiniteData,
UseInfiniteQueryResult,
UseQueryResult,
} from '@tanstack/react-query';

/**
* @name WatchServiceQueryWrapper
* @description higher order wrapper for components that are consuming useQueries.
* @returns JSX.Element
*/

export type SearchQueryWrapperType<
SData extends 'normal' | 'infinite',
TData,
UData extends SData extends 'normal'
? UseQueryResult<TData, Error>
: UseInfiniteQueryResult<InfiniteData<TData, unknown>, Error>
> = {
type: SData;
query: UData;
children: (
_props: Extract<UData, { isSuccess: true }>['data']
) => ReactElement;
fallbackLoader?: ReactElement;
fallbackError?: (
_props: Extract<UData, { isError: true }>['error']
) => ReactElement;
loaderOnRefetch?: boolean;
};

const SearchQueryWrapper = <
SData extends 'normal' | 'infinite',
TData,
UData extends SData extends 'normal'
? UseQueryResult<TData, Error>
: UseInfiniteQueryResult<InfiniteData<TData, unknown>, Error>
>({
query,
children,
fallbackLoader,
fallbackError,
loaderOnRefetch,
}: SearchQueryWrapperType<SData, TData, UData>) => {
// return loading
if (loaderOnRefetch ? query.isFetching : query.isLoading) {
return fallbackLoader || <p>loading...</p>;
}

// return error
if (!query.isSuccess) {
const error = query.isError
? query.error
: new Error('Something went wrong');
return fallbackError?.(error) || <p>{error.message}</p>;
}

// return child
return children(query.data);
};

export default SearchQueryWrapper;
fair-rose
fair-rose13mo ago
the problem is that those surrounding factors are very often the reason why something isn't working. By trying to reproduce in a sandbox, you can see if that's the case. see: https://tkdodo.eu/blog/how-can-i#3-provide-a-minimal-reproducible-example
How can I ... ?
Asking the right questions is a form of art that needs to be mastered.
fair-rose
fair-rose13mo ago
I'd first add the react-query-devtools to see what's going on in the cache
continuing-cyan
continuing-cyanOP13mo ago
yes, on that, these queries get fetched and go to inactive state if switched and this problem happens only on my amplify deployment not on local so i tried with changing my stale and gcTime but this keeps happening, should i try pushing devtools to prod to get a better insight
fair-rose
fair-rose13mo ago
if you change the filters, it's expected that the old filters go to inactive because they aren't used anymore

Did you find this page helpful?