React-Query: как использоватьQuery при нажатии кнопки

Я новичок в этой библиотеке запросов-ответов.

Я знаю, что когда я хочу получить данные, с помощью этой библиотеки я могу сделать что-то вроде этого:

const fetchData = async()=>{...}

// it starts fetching data from backend with this line of code
const {status, data, error} = useQuery(myKey, fetchData());

Оно работает. Но как запустить выборку данных только при нажатии кнопки?, Я знаю, что мог бы сделать что-то вроде<Button onPress={() => {useQuery(myKey, fetchData())}}/>, но как управлять возвращенными данными и статусом...

11 ответов

Согласно Справочнику API, вам необходимо изменитьenabledдля параметра false, чтобы отключить автоматический запуск запроса. Потом перекачиваешь вручную.

// emulates axios/fetch since useQuery expectes a Promise
const emulateFetch = async _ => {
  return new Promise(resolve => {
    resolve([{ data: "ok" }]);
  });
};

const handleClick = () => {
  // manually refetch
  refetch();
};

const { isLoading, error, data, refetch } = useQuery("key", emulateFetch, {
  refetchOnWindowFocus: false,
  enabled: false // turned off by default, manual refetch is needed
});

return (
  <div>
    <button onClick={handleClick}>Click me</button>
    {JSON.stringify(data)}
  </div>
);

Работа песочницы здесь.
Â

Отличная вещь о enabledвариант состоит в том, что вы передаете все, что возвращает логическое значение. Таким образом вы можете создавать зависимые / последовательные запросы.

// Get the user
const { data: user } = useQuery(['user', email], getUserByEmail)
 
// Then get the user's projects
const { isIdle, data: projects } = useQuery(
  ['projects', user.id],
  getProjectsByUser,
  {
    // `user` would be `null` at first (falsy),
    // so the query will not execute until the user exists
    enabled: user,
  }
)

Вы должны пройти manual: trueпараметр, чтобы запрос не загружался при монтировании. Также вы должны пройтиfetchDataбез скобок, поэтому вы передаете ссылку на функцию, а не значение. Для вызова запроса вы используете refetch().

const {status, data, error, refetch} = useQuery(myKey, fetchData, {
      manual: true,
    });

const onClick = () => { refetch() }

Обратитесь к разделу ручных запросов в документации по реакциям для получения дополнительной информации https://github.com/tannerlinsley/react-query

Похоже, что документация изменилась и сейчас отсутствует раздел ручных запросов. Однако, глядя на useQuery API, вам, вероятно, потребуется установитьenabled в false, а затем использовать refetchдля ручного запроса при нажатии кнопки. Вы также можете использоватьforce: true чтобы он запрашивал независимо от свежести данных.

Есть две проблемы сrefetch():

  • он отправит запрос на сервер, даже если ответ уже кэширован иstaleTimeне истек срок действия
  • вы не можете передать ему параметры

Если вам нужно сделать запрос по такому событию, какonClickилиonChange, использоватьqueryClient.fetchQuery().

      function MyComponent() {
  const queryClient = useQueryClient();

  const handleOnClick = async () => {
    const data = await queryClient.fetchQuery({ queryKey, queryFn });
  }

  return <button onClick={handleOnClick}>My Button</button>;
}

Вы можете видеть, что создатель и текущий сопровождающий рекомендуют этот подход.

Сначала реагирующий запрос дает нам включенную опцию, и по умолчанию это правда

      const fetchData = async()=>{...}

const {status, data, error , refetch} = useQuery(myKey, fetchData() , {
enabled : false
}
);

<button onClick={() => refetch()}>Refetch</button>

Вы можете попробовать эту версию:

      const fetchData = async()=>{...}

// it starts fetching data from backend with this line of code
const {status, data, error, refetch } = useQuery(
myKey, 
fetchData(),
{
  enabled: false,
}
);
const onClick = () => { refetch() }
// then use onClick where you need it

Из документации Doc:

enabled: boolean

  • Установите значение false, чтобы отключить автоматический запуск этого запроса.
  • Может использоваться для зависимых запросов.

refetch: (options: { throwOnError: boolean, cancelRefetch: boolean }) => Promise<UseQueryResult>

  • Функция для повторной загрузки запроса вручную.
  • В случае ошибок запроса, ошибка будет только записана. Если вы хотите, чтобы возникла ошибка, передайте throwOnError: true option
  • Если cancelRefetch является true, то текущий запрос будет отменен до того, как будет сделан новый запрос.

Есть еще один способ сделать это, который также работает, если вы хотите запускать несколько повторений.

      const [fetch, setFetch] = useState(null);
const query = useQuery(["endpoint", fetch], fetchData);

const refetch = () => setFetech(Date.now());

// call the refetch when handling click.

Если вы хотите обновить несколько сущностей, у вас может быть useState верхнего уровня, который вызывается, например, fetchAll и:

      ...
const query = useQuery(["endpoint", fetch, fetchAll], fetchData);
...

и этот код также сработает, если вы нажмете кнопку, чтобы получить все.

Если ключ тот же, используйте refetch(), если ключ другой, используйте useState для запуска запроса.

Например:

      const [productId, setProductId] = useState<string>('')
const {status, data, error, refetch} = useQuery(productId, fetchData, {
      enable: !!productId,
    });

const onClick = (id) => { 
if(productId === id) {
  refetch() 
}
else {
 setProductId(id)
}


}

В ответном запросе есть возможность useQuery() запускать перехват, когда вы захотите. Опция включена и принимает только логическое значение. Вот пример:

      const useGetAllUsers = useQuery({
    queryKey:["users"],
    queryFn: your_fetch_request,
    enabled: true|false
})

здесь вы можете передать любое логическое состояние из этого компонента.

Как упоминалось другими в этой теме, использование делает запрос, даже если кеш не устарел. Поэтому в идеале мы бы не звонилиquery.refetchтолько еслиquery.isFetched && !query.isStale. Я хотел инкапсулировать эту логику внутри хука, и вот как я это решил:

      // useGetFoo.ts
export const useGetFoo = () => {
  const query = useQuery({
    queryKey: ["foo"],
    queryFn: fetcher,
    enabled: false,
  });

  const fetch = (): ReturnType<typeof query.refetch> => {
    if (query.isFetching) return Promise.resolve(query);
    if (query.isFetched && !query.isStale && !query.isError)
      // browser hangs without this setTimeout
      return new Promise((resolve) => setTimeout(() => resolve(query)));
    return query.refetch();
  };

  return { ...query, fetch };
};

И тогда мы можем использовать его следующим образом:

      // SomeComponent.tsx
const { data, fetch: getFoo } = useGetFoo();

useEffect(() => {
  void getFoo();
}, [getFoo]);

вы можете использовать useLazyQuery()

      import React from 'react';
import { useLazyQuery } from '@apollo/client';

function DelayedQuery() {
   const [getDog, { loading, error, data }] = useLazyQuery(GET_DOG_PHOTO);

   if (loading) return <p>Loading ...</p>;
   if (error) return `Error! ${error}`;

   return (
      <div>
         {data?.dog && <img src={data.dog.displayImage} />}
         <button onClick={() => getDog({ variables: { breed: 'bulldog' } })}>Click me!</button>
      </div>
   );
}

ссылка: https://www.apollographql.com/docs/react/data/queries/#manual-execution-with-uselazyquery

Другие вопросы по тегам