Как мне использовать react-query для синхронного объединения данных из разных перехватчиков react-query вместе?

#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 , вы можете прочитать об этом здесь .