#javascript #reactjs #react-hooks #react-query
#javascript #reactjs #реагирующие перехватчики #react-query
Вопрос:
У меня есть три разных типа данных: Books
, Authors
, и Publishers
. Я использую react-query для извлечения списка каждого типа, т. Е. useBooks(bookIds)
, useAuthors(authorIds)
, usePublishers(publisherIds)
и это отлично работает, когда я пытаюсь использовать их независимо друг от друга.
Однако в книге есть список authorIds
and publisherIds
, и я хочу присоединить объекты Publishers
and Authors
к Books
. Я не могу понять, как правильно это сделать, используя react-query. В идеале я хотел бы иметь возможность вызывать все три перехвата, ждать их ответа, а затем возвращать его как один большой перехват. Однако я не могу обернуть голову, чтобы сделать это.
Одна из реализаций, которую я попробовал, заключалась в том, чтобы сделать каждый перехват, который соединяет данные Book
, зависимым от результатов предыдущего перехвата. Это работает нормально; однако большая проблема заключается в том, что соединения выполняются асинхронно друг от друга; данные, которые потребляет компонент, не могут ожидать, что a Book
будет иметь Author
или Publisher
после возврата данных. Вот пример:
const usePopulatedBooks = (bookIds) => {
const booksQuery = useBooks(bookIds);
const {data: books} = booksQuery;
const authorIds = [];
const publisherIds = [];
if (books) {
books.forEach(book => {
authorIds.push(book.authorId);
authorIds.push(book.publisherIds);
})
}
// Who knows when this finishes?
const {data: authors} = useAuthors(authorIds);
// Who knows when this finishes?
const {data: publishers} = usePublishers(publisherIds);
// Adds "author" and "publisher" field (if the authors/publishers array exist) to "book"
const joinedBooks = joinData(books, authors, publishers);
return {...booksQuery, data: joinedBooks};
}
Есть ли какой-нибудь способ, которым я могу написать приведенную выше логику таким образом, чтобы ничего не возвращалось, пока все данные не будут объединены? В моей голове способ, которым я бы это сделал, — вызвать все три перехвата в функции запроса другого перехвата react-query, но правила перехватов не позволяют мне этого делать.
Комментарии:
1. Есть ли у вас контроль над серверной частью / API? Если это так, то подобные проблемы было бы намного проще решить, просто имея конечную точку, которая предоставляет уже объединенные данные. Выполнение этого из интерфейса является болезненным без GraphQL.
Ответ №1:
Не зная, как ваши useBooks
, useAuthors
, и usePublishers
перехваты работают внутри, я не могу точно ответить, но я бы подошел к проблеме, написав функцию, которая выполняет все ваши вызовы API, а затем оберните эту единственную функцию useQuery
. Вы не хотите условно вызывать разные перехваты, поскольку это нарушает одно из правил перехватов: «Не вызывайте перехваты внутри циклов, условий или вложенных функций».
Что-то вроде этого:
async function getBookDetails() {
const books = await getAllBooks();
const authorIds = books.map(x => x.authorId);
const authors = await getAuthorsForIds(authorIds);
const publisherIds = books.map(x => x.publisherId);
const publishers = await getPublishersForIds(publisherIds);
return { books, authors, publishers };
}
Затем вы можете обернуть это в useQuery следующим образом:
const result = useQuery("book-details", getBookDetails);
Предполагается, что если нет результатов ни для одного из запросов, вы получаете пустой массив []
, а не null или undefined .
Если вы не знакомы с Array.map
, вы можете прочитать об этом здесь .