T
TanStack•14mo ago
variable-lime

Enabled sets data to undefined - solution?

Hi, having such a modal that is opened based on search params, I fetch user info and show a spinner or data after fetching. The problem appears when we close the modal - the enabled option, from what I see, immediately sets the data to undefined, and because of this, a spinner appears briefly when closing. I have no idea what to do to prevent this. Any ideas? Tanstack query v5 by the way.
export const UserModal = () => {
const [query, setQuery] = useQueryStates(userModalParsers);

const { data } = useQuery({
queryKey: ['user-info', query.userId],
staleTime: Infinity,
refetchOnWindowFocus: false,
enabled: Boolean(query.userId),
queryFn: () =>
getUserInfo({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Enabled
id: query.userId!
})
});

return (
<Dialog
open={Boolean(query.userId)}
onOpenChange={(open) => {
if (!open) {
void setQuery({
userId: null
});
}
}}
>
<DialogContent>{!data ? <Spinner /> : <p>User info</p>}</DialogContent>
</Dialog>
);
};
export const UserModal = () => {
const [query, setQuery] = useQueryStates(userModalParsers);

const { data } = useQuery({
queryKey: ['user-info', query.userId],
staleTime: Infinity,
refetchOnWindowFocus: false,
enabled: Boolean(query.userId),
queryFn: () =>
getUserInfo({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Enabled
id: query.userId!
})
});

return (
<Dialog
open={Boolean(query.userId)}
onOpenChange={(open) => {
if (!open) {
void setQuery({
userId: null
});
}
}}
>
<DialogContent>{!data ? <Spinner /> : <p>User info</p>}</DialogContent>
</Dialog>
);
};
v5 has an import keepPreviousData and this partially solves the problem - data is not set to undefined, but another problem appears: We click on user JOHN, there's loading => we fetch him => close the modal => click on user ANDRE => it shows the profile of user JOHN instead of loading => after a while it's the profile of ANDRE because it has loaded
10 Replies
variable-lime
variable-limeOP•14mo ago
This code fixes the issue - We check if user from keep previous data isn't the current userid from params but I am not sure if this is correct. Isn't there just a way to configure useQuery the way I want?
export const UserModal = () => {
const [query, setQuery] = useQueryStates(userModalParsers);

const { data } = useQuery({
queryKey: ['user-info', query.userId],
staleTime: Infinity,
refetchOnWindowFocus: false,
placeholderData: keepPreviousData,
enabled: Boolean(query.userId),
queryFn: () =>
getUserInfo({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Enabled
id: query.userId!
})
});

return (
<Dialog
open={Boolean(query.userId)}
onOpenChange={(open) => {
if (!open) {
void setQuery({
userId: null
});
}
}}
>
<DialogContent>{!data || (query.userId && query.userId !== data.id) ? <Spinner /> : <p>User info</p>}</DialogContent>
</Dialog>
);
};
export const UserModal = () => {
const [query, setQuery] = useQueryStates(userModalParsers);

const { data } = useQuery({
queryKey: ['user-info', query.userId],
staleTime: Infinity,
refetchOnWindowFocus: false,
placeholderData: keepPreviousData,
enabled: Boolean(query.userId),
queryFn: () =>
getUserInfo({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Enabled
id: query.userId!
})
});

return (
<Dialog
open={Boolean(query.userId)}
onOpenChange={(open) => {
if (!open) {
void setQuery({
userId: null
});
}
}}
>
<DialogContent>{!data || (query.userId && query.userId !== data.id) ? <Spinner /> : <p>User info</p>}</DialogContent>
</Dialog>
);
};
genetic-orange
genetic-orange•14mo ago
enabled does not set data to undefined. What happens is that you set userId: null, which means your queryKey changes towards: ['user-info', null],. The query now observers this key, and for that key, data is undefined. but also, with placeholderData: keepPreviousData,, you should still see the data from the previous queryKey. If you can make a minimal reproduction I can take a closer look
variable-lime
variable-limeOP•14mo ago
I do see data from the previous query key - that works as expected. And now I get it why the loading appears - what should I do then to not observe query key null?
variable-lime
variable-limeOP•14mo ago
GitHub
GitHub - stachujone5/react-query-dialog-fetch
Contribute to stachujone5/react-query-dialog-fetch development by creating an account on GitHub.
variable-lime
variable-limeOP•14mo ago
Create Next App
Generated by create next app
variable-lime
variable-limeOP•14mo ago
I'd like to remove this red loading square when we close the dialog so when the query key changes to null I am not sure why useQuery observes key ['user-info', null if we have this: enabled: !!userId
genetic-orange
genetic-orange•14mo ago
I do see data from the previous query key - that works as expected.
if that works then why is the spinner displayed ? probably your condition to render the spinner is wrong I'd only show the spinner if !data
variable-lime
variable-limeOP•14mo ago
Nah maybe I explained it the wrong way 😄 With keep previous data the spinner is only visible on the first user modal - then it never shows again But thats not what I'd like because when we click user 1 then user 2 while user2 is loading we are displaying user1 for a moment
genetic-orange
genetic-orange•14mo ago
then why do you use keepPreviousData at all ? the only thing it does is to show data from a previous query key while the current key is in hard loading state so that you don't need to show a spinner ... but it seems like you want to show a spinner 😂
variable-lime
variable-limeOP•14mo ago
In the provided example I didnt use it But keep previous data potentially fixes my problem which is this red square in the reproduction when closing dialog

Did you find this page helpful?