T
TanStack3y ago
exotic-emerald

useMutation firing and has a response, but does NOT return in "data

I have not run across this before, but I have a mutation, ala.
export default function useRegister(source) {
return useMutation(
async (payload) => {
const params = {
user: payload,
...(source && {source}),
};
const response = await user.registration(params);

if (response.err) {
const {status} = response.err;

throw new Error(response);
}
console.log("RESPONSE: ", response.data) // <-- this is good
return response.data;
},

{
onSuccess: data => {
// stuff
}
onError: (error) => {
// stuff
},
}
);
}
export default function useRegister(source) {
return useMutation(
async (payload) => {
const params = {
user: payload,
...(source && {source}),
};
const response = await user.registration(params);

if (response.err) {
const {status} = response.err;

throw new Error(response);
}
console.log("RESPONSE: ", response.data) // <-- this is good
return response.data;
},

{
onSuccess: data => {
// stuff
}
onError: (error) => {
// stuff
},
}
);
}
And on finish, data is undefined. I see the status go from "idle" => "loading" => "loading" => "idle". And the fetch is working, as I see the results in the console.log, but all the other attributes.. ala "isSuccess", "data", are all undefined..... What would be causing this behavior?
11 Replies
xenophobic-harlequin
xenophobic-harlequin3y ago
Some questions to help with debugging: - If you add console.log(data) inside onSuccess, do you get the correct data? - If you add console.log(error) inside onError, do you get anything? - If you remove the onSuccess and onError callbacks (just for testing), do you see the same behaviour? - Any error in the console?
exotic-emerald
exotic-emeraldOP3y ago
Hey Julien, "onSuccess" is good too - onError does not get any errors. But, when it makes it back to the return, I get:
{
"context": undefined
"data": undefined
"error": null,
"failureCount": 0,
"isPaused": false,
"status": "idle",
"isLoading": false,
"isSuccess": false,
"isError": false,
"isIdle": true
...
}
{
"context": undefined
"data": undefined
"error": null,
"failureCount": 0,
"isPaused": false,
"status": "idle",
"isLoading": false,
"isSuccess": false,
"isError": false,
"isIdle": true
...
}
Also, i know the fetch is working and onSuccess because my "state" IS updating... (I added a setQueryData) in the success.. and I see it in my react query tools ---- it just does NOT return in "data".
xenophobic-harlequin
xenophobic-harlequin3y ago
That's odd, I couldn't find any issue in the code you pasted. Would you be able to share a minimal reproduction in a sandbox?
exotic-emerald
exotic-emeraldOP3y ago
I think the issue is that in the "onSuccess" I call a helper function that does "additional" code updates. There are no errors in that code, but the abstraction seems to be at issue... because i am updating this code in various mutations, I wanted to centralize it... ala.. the abstraction... but it seems it mucks up the returning of data???
//THIS WORKS, BUT when a abstracted out function
// it does not.

onSuccess: user => {
// some destructuring..

queryClient.setQueryData(userQueryKeys.all, (prevData = {}) => ({...(prevData as User), ...user}));
queryClient.setQueryData(userQueryKeys.auth, {
authToken: user.authToken,
});
//
/* Set Third Party Users */
IOChat?.hideChat?.();
IOChat?.identify?.(user.io.jwt);
Bugsnag?.setUser?.(id as string, name, email as string);
//THIS WORKS, BUT when a abstracted out function
// it does not.

onSuccess: user => {
// some destructuring..

queryClient.setQueryData(userQueryKeys.all, (prevData = {}) => ({...(prevData as User), ...user}));
queryClient.setQueryData(userQueryKeys.auth, {
authToken: user.authToken,
});
//
/* Set Third Party Users */
IOChat?.hideChat?.();
IOChat?.identify?.(user.io.jwt);
Bugsnag?.setUser?.(id as string, name, email as string);
When abstracted out, it does NOT return "data". When I put it inline, it works fine. Why would that be? Isn't "onSuccess" where I want side effects? Shouldn't matter if I abstract out.. So, I just did a simple test.. in the onSuccess instead of calling:
queryClient.setQueryData('yourkey', (prevData = {}) => ({...(prevData as User), ...user}));
queryClient.setQueryData('yourkey', (prevData = {}) => ({...(prevData as User), ...user}));
I called a method that executed the above... ala..
const updateGlobalConcerns = (user) => {
queryClient.setQueryData('yourkey', (prevData = {}) => ({...(prevData as User), ...user}));
}
const updateGlobalConcerns = (user) => {
queryClient.setQueryData('yourkey', (prevData = {}) => ({...(prevData as User), ...user}));
}
so I did:
onSuccess: data => {
updateGlobalConcerns(data); // Nope....
}
onSuccess: data => {
updateGlobalConcerns(data); // Nope....
}
doesn't work... why would that be? So weird. Try it, I just did it with a simple thing as shown above.. even a single setQueryData set in a function that I call.....
xenophobic-harlequin
xenophobic-harlequin3y ago
When abstracted out, it does NOT return "data". When I put it inline, it works fine
Can you show the actual complete code, the version that works and the one that doesn't work?
exotic-emerald
exotic-emeraldOP3y ago
WORKS:
export default function useUserMutationRegister(source) {
return useMutation(
async (payload) => {
const params = {
user: payload,
...(source && {source}),
};
const response = await user.registration(params);

return response.data;
},

{
/* Update user */
onSuccess: data => {
const {authToken} = data.user ?? {};

if (authToken) {
const {id, name, email} = user;

queryClient.setQueryData(userQueryKeys.all, (prevData = {}) => ({...prevData, ...user}));
queryClient.setQueryData(userQueryKeys.auth, {
authToken: user.authToken
});

/* Set Third Party Users */
IOChat?.hideChat?.();
IOChat?.identify?.(user.iochat);
Bugsnag?.setUser?.(id, name, email);
}

},

onError: (error) => {
displayErrors(error);

Logger('useUserMutationLogin')(error);
},
}
);
}
export default function useUserMutationRegister(source) {
return useMutation(
async (payload) => {
const params = {
user: payload,
...(source && {source}),
};
const response = await user.registration(params);

return response.data;
},

{
/* Update user */
onSuccess: data => {
const {authToken} = data.user ?? {};

if (authToken) {
const {id, name, email} = user;

queryClient.setQueryData(userQueryKeys.all, (prevData = {}) => ({...prevData, ...user}));
queryClient.setQueryData(userQueryKeys.auth, {
authToken: user.authToken
});

/* Set Third Party Users */
IOChat?.hideChat?.();
IOChat?.identify?.(user.iochat);
Bugsnag?.setUser?.(id, name, email);
}

},

onError: (error) => {
displayErrors(error);

Logger('useUserMutationLogin')(error);
},
}
);
}
DOES NOT WORK
export default function useUserMutationRegister(source) {
return useMutation(
async (payload) => {
const params = {
user: payload,
...(source && {source}),
};
const response = await user.registration(params);

return response.data;
},

{
/* Update user */
onSuccess: data => {
const {authToken} = data.user ?? {};

if (authToken) {
updateContingencies(data.user);
}

},

onError: (error) => {
displayErrors(error);

Logger('useUserMutationLogin')(error);
},
}
);
}
export default function useUserMutationRegister(source) {
return useMutation(
async (payload) => {
const params = {
user: payload,
...(source && {source}),
};
const response = await user.registration(params);

return response.data;
},

{
/* Update user */
onSuccess: data => {
const {authToken} = data.user ?? {};

if (authToken) {
updateContingencies(data.user);
}

},

onError: (error) => {
displayErrors(error);

Logger('useUserMutationLogin')(error);
},
}
);
}
xenophobic-harlequin
xenophobic-harlequin3y ago
The only thing I can think of is updateContingencies() not having access to some of the variables (queryClient, IOChat, Bugsnag etc...), or an error somehow being thrown in there. I would investigate this by emptying out updateContingencies() (start with an empty function), make sure it works, and then adding back each line (first setQueryData, second setQueryData, IOChat?.hideChat?.(); etc...) one at a time and see where it breaks (= when the data returned from the hook is undefined).
exotic-emerald
exotic-emeraldOP3y ago
cool, yeah - I did all that - I'll try it again, maybe in my irritation I let something slide. thanks.
harsh-harlequin
harsh-harlequin3y ago
If you could provide a minimal runnable reproduction such as a Code Sandbox we can take a closer look for you
exotic-emerald
exotic-emeraldOP3y ago
I find that the issue is this. UPDATE: Why does this work? // this is just a wrapper for a setTimeout. But sets it, as 0, to the next event loop. // so, why would this be ok ?? soo weird. sleep(0).then(() => { updateContingencies(data.user); })
export const updateContingencies = (user: User) => {

/* THIS breaks it... */
queryClient.setQueryData(userQueryKeys.all, user);

/* THIS DOES NOT - THIS IS FINE */
queryClient.setQueryData(userQueryKeys.auth, {
authToken: user.authToken,
formAuthenticityToken: user.formAuthenticityToken,
});

// removed all the other updating things
};
export const updateContingencies = (user: User) => {

/* THIS breaks it... */
queryClient.setQueryData(userQueryKeys.all, user);

/* THIS DOES NOT - THIS IS FINE */
queryClient.setQueryData(userQueryKeys.auth, {
authToken: user.authToken,
formAuthenticityToken: user.formAuthenticityToken,
});

// removed all the other updating things
};
When I remove that offending "setQueryData", it all works.. when I remove it and put it IN the files that need it (I still include the "updateContingencies(user)" call, but just put the setQueryData above it, it works... something about THAT particular "setQueryData" in a seperate file??? Nevermind on that last bit. It doesn't work even when within the onSuccess. Mind you, the cache IS udpated, it just doesn't allow for the mutation/query to return data. It's always undefined, unless I remove that setQueryData. I also wrapped it in a try/catch, no errors. (but there shoudln' be as the cache is updating, as mentioned). Also what is odd, "IF" I change the queryKey to anything else ala "foo", it works - I can't understand how my common queryKey.. "userQueryKeys.all" is having side effects. so,
/* THIS breaks it... */
queryClient.setQueryData(userQueryKeys.all, user);

/* THIS DOES NOT */
queryClient.setQueryData(['whatever_dude'], user);
/* THIS breaks it... */
queryClient.setQueryData(userQueryKeys.all, user);

/* THIS DOES NOT */
queryClient.setQueryData(['whatever_dude'], user);
xenophobic-harlequin
xenophobic-harlequin3y ago
What is the value of userQueryKeys.all?

Did you find this page helpful?