简体   繁体   English

如何使用 react-query 将来自不同 react-query 钩子的数据同步连接在一起?

[英]How do I use react-query to synchronously join data from different react-query hooks together?

I have three different data types: Books , Authors , and Publishers .我有三种不同的数据类型: BooksAuthorsPublishers I use react-query to fetch a list of each type, ie useBooks(bookIds) , useAuthors(authorIds) , usePublishers(publisherIds) and this works great when I try to use them independently of each other.我使用 react-query 来获取每种类型的列表,即useBooks(bookIds)useAuthors(authorIds)usePublishers(publisherIds) ,当我尝试独立使用它们时,这非常有效。

However, a book has a list of authorIds and publisherIds and I want to join the Publishers and Authors objects to the Books .但是,一本书有一个authorIdspublisherIds列表,我想将PublishersAuthors对象加入Books I can't figure out the right way to do this using react-query.我无法找出使用 react-query 执行此操作的正确方法。 Ideally I'd like to be able to call all three hooks, wait for their response, and then return it as one big hook.理想情况下,我希望能够调用所有三个钩子,等待他们的响应,然后将其作为一个大钩子返回。 However, I cannot wrap my head around to do this.但是,我无法做到这一点。

One implementation I tried was to make each hook that joins data to Book dependent on the results of a previous hook.我尝试过的一个实现是让每个将数据连接到Book钩子都依赖于前一个钩子的结果。 This works okay;这工作正常; however the big problem with this is that the joins are done asynchronously from one another;然而,最大的问题是连接是彼此异步完成的; the data the component consumes cannot expect a Book to have a Author or Publisher once the data is returned.一旦数据返回,组件使用的数据就不能期望BookAuthorPublisher Here's an example:下面是一个例子:

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};
}

Is there some way I can write the above logic in a way such that nothing returns until all data has been joined?有什么方法可以编写上述逻辑,以便在所有数据都加入之前不会返回任何内容? In my head the way I'd do this is call all three hooks in a query function of another react-query hooks, but hooks rules don't let me do this.在我的脑海中,我这样做的方式是在另一个 react-query 钩子的查询函数中调用所有三个钩子,但是钩子规则不允许我这样做。

Without knowing how your useBooks , useAuthors , and usePublishers hooks work internally, I can't answer precisely, but I'd approach the problem by writing a function that does all your API calls, then wrap that single function with useQuery .在不知道useBooksuseAuthorsusePublishers钩子内部如何工作的情况下,我无法准确回答,但我会通过编写一个执行所有 API 调用的函数来解决这个问题,然后用useQuery包装该单个函数。 You don't want to conditionally call different hooks as that violates one of the rules of hooks : "Don't call Hooks inside loops, conditions, or nested functions."您不想有条件地调用不同的钩子,因为这违反了钩子规则之一:“不要在循环、条件或嵌套函数内调用钩子。”

Something like this:像这样的东西:

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 };
}

Then you can wrap it in a useQuery like this:然后你可以将它包装在一个 useQuery 中,如下所示:

const result = useQuery("book-details", getBookDetails);

This assumes that if there are no results for any of the queries, you get an empty array [] , not null or undefined.这假设如果任何查询都没有结果,您将获得一个空数组[] ,而不是 null 或未定义。

If you're not familiar with Array.map , you can read up on it here .如果您不熟悉Array.map ,可以在此处阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM