3

我有三种不同的数据类型:BooksAuthorsPublishers。我使用 react-query 来获取每种类型的列表,即useBooks(bookIds), useAuthors(authorIds)usePublishers(publisherIds)当我尝试相互独立地使用它们时,这非常有用。

但是,一本书有一个 and 的列表,authorIdspublisherIds想将PublishersandAuthors对象加入到Books. 我想不出使用 react-query 的正确方法。理想情况下,我希望能够调用所有三个钩子,等待它们的响应,然后将其作为一个大钩子返回。但是,我不能绕着头来做这件事。

我尝试的一种实现是使每个连接数据的钩子都Book依赖于前一个钩子的结果。这行得通;然而,最大的问题是连接是彼此异步完成的;组件使用的数据不能期望 aBook有 aAuthorPublisher一旦返回数据。这是一个例子:

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 钩子的查询函数中调用所有三个钩子,但钩子规则不允许我这样做。

4

1 回答 1

5

在不知道您的useBooksuseAuthorsusePublishers钩子如何在内部工作的情况下,我无法准确回答,但我会通过编写一个执行所有 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 或未定义。

如果你不熟悉Array.map,你可以在这里阅读。

于 2020-10-29T00:50:21.387 回答