Как получить n зависимых данных с помощью response-query
Мне нужна помощь с библиотекой реагирующих запросов. Я получаю список объектов, а затем для всех, кто мне нужен, получаю дополнительные данные из другой службы. Как мне сделать это с помощью response-queryuseQuery
крючок?
Пример 1:
const { data} = useQuery("USERS", fetchUsers);
data.map(user => useQuery(["ACCOUNT", {userId: user.id}],
({userId}) => fetchAccount(userId)));
Ошибка:
ESLint: React Hook
useQuery
нельзя вызвать внутри обратного вызова. React Hooks необходимо вызывать в компоненте функции React или в пользовательской функции React Hook. (перехватчики реакции / перехватчики правил)
7 ответов
Это похоже на текущее решение, по крайней мере, для ответа на запрос v3:
// Get the user
const { data: user } = useQuery(['user', email], getUserByEmail)
const userId = user?.id
// Then get the user's projects
const { isIdle, data: projects } = useQuery(
['projects', userId],
getProjectsByUser,
{
// The query will not execute until the userId exists
enabled: !!userId,
}
)
// isIdle will be `true` until `enabled` is true and the query begins to fetch.
// It will then go to the `isLoading` stage and hopefully the `isSuccess` stage :)
Я нашел ответ, предоставленный автором response-query:
Из того, что вы описали, похоже, что это классическая фраза "Я хочу использовать перехватчики React в режиме массива", в которой мы все определенно были раньше.
В 99,9% случаев я чувствую, что ответ на это затруднительное положение состоит в том, чтобы отрендерить использование хуков в несколько компонентов и скомпоновать их результаты после рендеринга, но здесь определенно есть крайние случаи и множество компромиссов. Однако это лучшее решение, которое у нас есть на данный момент, поскольку нет отличного способа использовать MapHooks(item => useQuery(item), items). Это было бы действительно здорово, но поверьте мне, я пошел по этому пути, и хотя у меня действительно кое-что работало более или менее, это в конечном итоге усложнило мой код намного больше, чем я ожидал. В настоящее время React Query, скорее всего, не получит ту функцию, о которой вы говорите, поскольку сама библиотека использует хуки, она привязана к той же механике, что и вы, и потребует огромного количества переархивирования, чтобы хотя бы приблизиться к тому, что вы ' повторное описание.Окупаемость инвестиций не окупится и, скорее всего, снизит производительность, размер и сложность API для остальной части библиотеки.
Чтобы решить вашу конкретную проблему на сегодня, я бы предложил три возможных решения:
Ничего страшного, если запрашивается информация о нескольких столбцах, даже если вам нужен только один. Отрегулируйте запоминание / потребление этой информации в столбцах, чтобы обновлять только в том случае, если они новые. Это значительно упростит задачу и, вероятно, позволит вам двигаться вперед быстрее.
Составьте запросы сборщика информации о столбцах в несколько компонентов, которые ничего не отображают, и вместо этого передайте им опору, которая позволяет им сообщать свои результаты обратно родительскому компоненту, а затем объединять их результаты в родительском компоненте в один массив столбцов.
Создайте свой собственный небольшой "кеш" для хранения списка уже извлеченной информации о столбцах, а затем объедините свою логику извлечения в один запрос. Используйте свой настраиваемый объект кеша, чтобы заполнять слоты в этом массиве, когда данные доступны, а также поддерживать их в актуальном состоянии, очищая кеш так часто, как вы считаете нужным. Я бы рассмотрел это в крайнем случае, так как вы, по сути, начнете управлять своим собственным кешем, а это именно то, что React Query предназначен для вас. Если вы это сделаете, я бы посоветовал взвесить здесь все преимущества, которые вы получаете с React Query. Это может быть крайний случай, когда стратегия кэширования / выборки React Query не подходит, и это нормально.
Надеюсь это поможет!
Используйте зависимые запросы, - пока data
(users) разрешено, то ваша вторая строка ключа запроса должна быть ложной, пока у вас не появятся пользователи:
// rename `data` to `users`
const { data: users } = useQuery("USERS", fetchUsers);
// `users` causes query key to be falsy until they are loaded
// rename `data` to `accounts`, map `users` id only and pass to pass in as param
const { data: accounts } = useQuery([users && "ACCOUNT", users.map((u) => u.id)], async (key, userIds) => {
const response = await fetchAccounts(userIds);
// TODO any mapping?
return response;
});
Я делаю этот код просто для меня, он отлично работает, реагируя на зависимый документ запроса
const { yokooUser } = useFirebase()
// load all bookings using react query nad current user email
const { isError, error, status, data } = useQuery(
['myOrders', yokooUser.email], async () => await axios.get(`http://localhost:5000/booking/${yokooUser.email}`,
{
// The query will not execute until the userId exists
enabled: !!yokooUser.email,
}
))
if (status === 'loading') {
return <div>Loading...</div>;
}
// error message query
if (isError) {
return <div>Error: {error.message}</div>;
}
import { useQuery } from 'react-query';
const fetchData = async (url) => {
const response = await fetch(url);
return response.json();
};
const ParentComponent = () => {
const { data: firstData, refetch: refetchFirst } = useQuery('firstQuery', () => fetchData('/api/first'));
const { data: secondData, refetch: refetchSecond } = useQuery(
['secondQuery', firstData], // Invalidate on changes to firstData
() => fetchData(`/api/second/${firstData.id}`),
{
enabled: !!firstData, // Only enable when firstData is available
}
);
// Additional nested queries...
return (
<div>
{/* Render based on firstData and secondData */}
</div>
);
};
Я начал использовать для этого другую технику, когда я делаю оба вызова из функции «получить». Преимущество заключается в сокрытии сложности API за функцией. Недостатком является менее детальный контроль над компонентом.
Ниже приведен пример (не проверенный), похожий на то, что я обычно делаю.
const getProjectsByUser = () => {
// I'm using axios, but you can use fetch or something else.
const {data} = axios.get("/api/user")
// Let's assume the user endpoint returns a user with an array of projects
const projectNames = data.user.projects
const fetchProjects = projecNames.map(name => axios.get(`/api/projects/${name}`)
// I may use Promise.all or Promise.allSettled
const projResponses = await Promise.all(fetchProjects)
return projResponses.data;
}
Единственный код на каком-то компоненте:
import {getProjectsByUser } from "some path"
const { data: user } = useQuery(['user', email], getProjectsByUser)
const userId = user?.id
В документации по ответному запросу вы можете найти параллельный запрос, в котором объясняется ваша проблема, которую вы можете сделать, если вам нужны два данных.
const { data} = useQuery("USERS", fetchUsers);
const {data:fetchAccount} = useQuery('Account , {userId: user.id}] ,fetchAccount)))
fetchAccount.map((item)=>{
return (
<div key={item.id}>{item.stuffs}</div>
)
}