arunmmanoharan
arunmmanoharan

Reputation: 2675

react-query with rules of hook broken error

I am trying to extract my API calls using react-query into a reusable hook. The parameters I need to send to this hook are moduleName and value. For some reason, I get an error that I need to follow hooks rules.

Please advice.

This is my code:

export const useAutoSave = () => {
  const fetcher = useCallback(
    (
      moduleName: ISourceLoaderEditTabs,
      value: Partial<ISourceConfigurationEdit[ISourceLoaderEditTabs]>,
      saveUrl = '',
    ) => {
      const handleSaveSourceDetailsMutation = useMutation(
        (data: ISourceConfigurationEdit) =>
          saveUrl
            ? postSaveStageRaw(`${POST_SAVE_STAGE_RAW}?${saveUrl}`, data)
            : saveSourceDetails(data),
      );
      const sourceId = sessionStorage.getItem('sourceId');

      const sourceDetail = queryClient.getQueryData([
        'getSourcesDetail',
        Number(sourceId),
      ]);
      handleSaveSourceDetailsMutation.mutate(
        {
          ...(sourceDetail as ISourceConfigurationEdit),
          [moduleName]: {
            ...(sourceDetail as ISourceConfigurationEdit)[moduleName],
            ...value,
          },
        },
        {
          onSuccess: async (data) => {
            queryClient.setQueryData(
              ['getSourcesDetail', Number(sourceId)],
              data,
            );
          },
        },
      );
    },
    [],
  );

  return [fetcher];
};

Then in my component I use it as

const [fetch] = useAutoSave();

fetch('abc', {
  name:'a2441918'
})

enter image description here

Code snippet : Stackblitz: https://stackblitz.com/edit/react-q8uvse?file=src%2Fhooks.js

Upvotes: 0

Views: 861

Answers (2)

TkDodo
TkDodo

Reputation: 29056

you cannot call useMutation inside useCallback. Also, you don't need to. useMutation returns one object with two functions - mutate and mutateAsync, that you can invoke when you want to call invoke your mutation. So your custom hook very likely should only return whatever useMutation returns. The fist argument to useMutation is the mutateFn - the function that is called when you invoke mutate or mutateAsync, and you can also pass one parameters object there:

const useAutoSave = () => {
  return useMutation(
   ({ moduleName, value, saveUrl }) => saveUrl
        ? postSaveStageRaw(`${POST_SAVE_STAGE_RAW}?${saveUrl}`, data)
        : saveSourceDetails(data),
  )
}

you can then invoke it via:

const { mutate } = useAutoSave()

<button onClick={() => {
  mutate({ moduleName: 'something, value: 'somethingElse' })
}}>Save</button>

Upvotes: 1

Karthik R
Karthik R

Reputation: 5786

The issue as it states in the error log - usage of useMutation

const handleSaveSourceDetailsMutation = useMutation(
        (data: ISourceConfigurationEdit) =>
          saveUrl
            ? postSaveStageRaw(`${POST_SAVE_STAGE_RAW}?${saveUrl}`, data)
            : saveSourceDetails(data),
      );

This useMutation hook needs to be outside of the useCallback. This also means that the saveUrl and other params need to be refactored.

export const useAutoSave = () => {
  const i_dont_know = useMutation(x,x,x,x); // hooks can't be called in regular functions 
}

Rules of hook for reference: https://reactjs.org/docs/hooks-rules.html

Upvotes: 0

Related Questions