Условный вызов 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, но enable
option может принимать любое логическое значение. В этом случае - если строка поискового запроса достаточно длинная.
Есть еще один вариант, который заключается в использованииqueryClient.fetchQuery
API, который дает вам возможность условно вызывать запрос для получения данных.
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}- </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 });