Search code examples
reactjstypescriptreact-querytanstackreact-query

getQueryData always returns undefined even when set with useMutation - TanStack Query, React


When I try to read cache content of given key I receive undefined even after I call useMutation with exactly same key.

Mutation used to set cache (mutation returns proper data, as expected):

const axiosInstance = axios.create(habiticaAPIconf);

function parseResponse(response:LoginDataContract):AuthData{
  return {
    id: response.data.id,
    apiToken: response.data.apiToken,
    username: response.data.username
  }
}

const getAuthenticationData = async (userCredentials:UserCredentials):Promise<AuthData> => {
  const response = await axiosInstance.post<LoginDataContract>("/user/auth/local/login", {...userCredentials});
  return parseResponse(response.data);
}

export function useCredentialData() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (loginData:UserCredentials):Promise<AuthData> => getAuthenticationData(loginData),
    mutationKey: ['authData']
  });
};

Component used to fire the mutation:

export function LoginForm() {
  const { mutate, isSuccess, data } = useCredentialData();

  function handleLogin(e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>) {
    e.preventDefault();
    mutate({
      username: (document.getElementById("email") as HTMLInputElement).value,
      password: (document.getElementById("password") as HTMLInputElement).value
    });
    console.log(data);
  }

  return (
    <form>
      <label htmlFor="email">
        <input type="email" name="email" id="email"></input>
      </label>
      <label htmlFor="password">
        <input type="password" name="password" id="password"></input>
      </label>
      <button type="submit" onClick={ (e)=> {handleLogin(e)}}>Login</button>
      <span>{isSuccess ? `${data.username}` : ""}</span>
    </form>
  )
}

While clicking button in React Component undefined is always received even after abovementioned mutatuion is called and returns proper data.

import { useQueryClient } from "@tanstack/react-query";

export function SidebarTasksList() {
  const queryClient = useQueryClient();

  return (
    <section>
      <button onClick={
        ()=>console.log(queryClient.getQueryData(['authData']))
      }>CLICK</button>
    </section>
  );

How to retrive data stored in ['AuthData'] cache? There is no function I could pass to useQuery as queryFn either, that's why I'm tring with getQueryData.


Solution

  • Generally speaking, mutations and queries have no correlation. Setting the same key on both of them does not achieve that they know about each other. The mutationKey is also optional. None of the examples actually set the key if I remember correctly because it's mostly used to share configuration between mutations.

    What you need to do to "link" the result of your mutations to your queries is to either:

    • invalidate the query in response to the successful mutation. This is the path with the least code, as it will just re-fetch from the server:
      return useMutation({
        mutationFn: (loginData:UserCredentials):Promise<AuthData> => getAuthenticationData(loginData),
        onSuccess: () => queryClient.invalidateQueries(['authData'])
      });
    
    • if your API call returns data, you can use that to manually write to the cache. This is more code, but one less round-trip to the server:
      return useMutation({
        mutationFn: (loginData:UserCredentials):Promise<AuthData> => getAuthenticationData(loginData),
        onSuccess: (data) => queryClient.setQueryData(['authData'], data)
      });