Как можно переписать useMutation в useQuery, чтобы затем иметь возможность вызывать invalidateQueries?

Как можно изменить данный код, чтобы он работал так же, как и ранее? <br/> <br/> <pre><code class="typescript">import { authService } from '@/services/auth.service';
import { useUserStore } from '@/store/use-user-store';
import { useMutation } from '@tanstack/react-query';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react';

const FetchUser = ({ children }: React.PropsWithChildren) =&gt; {
	const { setIsAuth, setUser, setIsLoading } = useUserStore();
	const pathname = usePathname();

	const { mutate } = useMutation({
		mutationKey: ['verify-auth'],
		mutationFn: () =&gt; authService.getNewTokens(),
		onSuccess(data) {
			setIsAuth(true);
			setUser(data.data.user);
		},
		onError(error) {
			setIsAuth(false);
			setUser(null);
			// console.log('ERROR ', error);
		},
		onMutate() {
			setIsLoading(true);
		},
		onSettled() {
			setIsLoading(false);
		},
	});

	useEffect(() =&gt; {
		mutate();
	}, [pathname]);

	return &lt;&gt;{children}&lt;/&gt;;
};

export default FetchUser;</code></pre>
  • 24 октября 2024 г. 5:22
Ответы на вопрос 2
Чтобы переписать `useMutation` в `useQuery`, и потом иметь возможность вызывать `invalidateQueries`, нужно немного изменить логику вашего компонента. Вместо использования мутации для вызова функции получения токенов, вы можете создать запрос для получения данных, и дополнительно обработать результаты, чтобы обновить состояние вашего приложения.

Вот переписанный код:

```typescript
import { authService } from '@/services/auth.service';
import { useUserStore } from '@/store/use-user-store';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react';

const FetchUser = ({ children }: React.PropsWithChildren) => {
	const { setIsAuth, setUser, setIsLoading } = useUserStore();
	const pathname = usePathname();
	const queryClient = useQueryClient();

	const { data, error, isLoading } = useQuery({
		queryKey: ['verify-auth'],
		queryFn: authService.getNewTokens,
		refetchOnWindowFocus: false, // если не нужно обновлять на фокусе
		onSuccess(data) {
			setIsAuth(true);
			setUser(data.data.user);
		},
		onError() {
			setIsAuth(false);
			setUser(null);
		},
	});

	useEffect(() => {
		if (pathname) {
			setIsLoading(true);
			queryClient.invalidateQueries(['verify-auth']);
		}
	}, [pathname, queryClient]);

	useEffect(() => {
		setIsLoading(isLoading);
	}, [isLoading]);

	if (isLoading) return <div>Loading...</div>; // Можно отобразить загрузку
	if (error) return <div>Error: {error.message}</div>; // Обработка ошибки

	return <>{children}</>;
};

export default FetchUser;
```

### Объяснение изменений:

1. **Использование `useQuery`**: Вместо `useMutation`, вы используете `useQuery`, который автоматически осуществляет запрос данных. Это позволяет отслеживать состояние загрузки и ошибок.
   
2. **`invalidateQueries`**: В `useEffect` вы вызываете `invalidateQueries`, чтобы обновить данные при смене `pathname`. `queryClient` инъектируется с помощью `useQueryClient`, что позволяет вам управлять кэшированными запросами.

3. **Обработка состояния загрузки и ошибок**: Добавлено условие для отрисовки индикатора загрузки или сообщения об ошибке.

Таким образом, компонент теперь использует `useQuery` для получения данных, при этом сохраняется возможность обновления запросов с помощью `invalidateQueries` при изменении пути.
В наглую как-то так 
export const useVerifyAuth = () => {
  const { setIsAuth, setUser, setIsLoading } = useUserStore();
  const pathname = usePathname();

  const { data, error, isLoading, isFetching, refetch } = useQuery({
    queryKey: ["verify-auth"],
    queryFn: () => authService.getNewTokens()
  });

  useLayoutEffect(() => {
    if (error !== null) {
      setIsAuth(false);
      setUser(null);
    }

    if (data !== null) {
       setIsAuth(true);
       setUser(data.data.user);
    }
  }, [data, error])

  useEffect(() => {
    // Тут бы проверить, что прошлый pathname не равен текущему
    refetch();
  }, [pathname, refetch]);

  useEffect(() => {
    setIsLoading(isLoading || isFetching)
  }, [isLoading, isFetching]);
};
Похожие вопросы