Условный вызов API с помощью перехватчика React-Query

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

У меня есть поле ввода, где пользователи вводят поисковый запрос. При изменении входного значения вызывается поисковый сервер с содержимым входных данных в качестве поискового запроса... но только если входное значение превышает 3 символа.

В моем реагирующем компоненте я звоню:

const {data, isLoading} = useQuery(['search', searchString], getSearchResults);

И мой getSearchResults функция условно выполнит вызов API.

const getSearchResults = async (_, searchString) => {
    if (searchString.length < 3)
        return {data: []}

    const {data}  = await axios.get(`/search?q=${searchString}`)
    return data;
}

Мы не можем использовать ловушку внутри условного оператора, поэтому я помещаю условие в свою вызывающую функцию API.

Это почти работает. Если я введу короткую строку запроса, запрос API не будет выполнен, и я верну пустой массив дляdata. Ура!

Но - isLoading перевернется на trueвкратце - даже если HTTP-запрос не выполняется. Так что мой индикатор загрузки показывает, когда нет реальной сетевой активности.

Я не понимаю, как лучше всего решить мой вариант использования, есть ли способ убедиться, что isLoading вернет false, если нет активности HTTP?

3 ответа

Ключевым моментом было использование зависимых запросов

Итак, в моем основном компоненте я создаю логическое значение и передаю его в enabled вариант useQuery крючок:

const isLongEnough = searchString.length < 3
const {data, isLoading} = useQuery(['search', searchString], getSearchResults, {enabled: isLongEnough});

а метод вызова API - это просто вызов API, а не условный:

const getSearchResults = async (_, searchString) => {
    const {data}  = await axios.get(`/search?q=${searchString}`)
    return data;
}

Документы описывают зависимые запросы как решение для загрузки данных из последующих конечных точек API, но enableoption может принимать любое логическое значение. В этом случае - если строка поискового запроса достаточно длинная.

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

      function Example2() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  if (isLoading) return "Loading...";

  if (error) return "An error has occurred: " + error;

  return (
    <div>
      <button
        onClick={async () => {
          try {
            setIsLoading(true);
            const posts = await queryClient.fetchQuery(
              ["postsUsingFetchQuery"],
              {
                queryFn: () =>
                  axios
                    .get("https://jsonplaceholder.typicode.com/posts")
                    .then((res) => res.data)
              }
            );
            setData(posts);
          } catch (e) {
            setError(e);
          }
          setIsLoading(false);
        }}
      >
        Fetch posts using fetchQuery{" "}
      </button>
      <h1>Posts</h1>
      {data?.map((post) => {
        return (
          <div style={{ display: "flex" }}>
            <span>{post.id}-&nbsp;</span>
            <div>{post.title}</div>
          </div>
        );
      })}
    </div>
  );
}

В обработчик нажатия кнопки мы добавили реализацию для получения сообщений с помощью queryClient.fetchQuery.

Вы можете прочитать больше по этой ссылке.

More simple solution, just add:{ enabled: isAutoFetching }

Exemple:

      useQuery("launches", async () => {
    const response = await fetch("http://localhost:3000/graphql/", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ query: query })
    });
    if (response.status >= 400) {
      throw new Error("Error fetching data");
    } else {
      return response.json();
    }
  }, { enabled: isAutoFetching }); 
Другие вопросы по тегам