T
TanStack6mo ago
like-gold

Non-undefined placeholderData types as possibly undefined

If my placeholderData function always returns a proper result (not undefined), then why is the resulting data property typed as T | undefined? Consider the following example:
function useBook() {
const bookId = useBookId();

return useQuery({
queryKey: ["book", bookId] as ["book", number],
queryFn: ({queryKey: [, bookId]}) => fetchBook(bookId),
placeholderData: (previousBook) => previousBook ?? {id: 123, title: "Default Book"},
});
}

function useBookTitle() {
const {data: book} = useBook();
return book.title;
}
function useBook() {
const bookId = useBookId();

return useQuery({
queryKey: ["book", bookId] as ["book", number],
queryFn: ({queryKey: [, bookId]}) => fetchBook(bookId),
placeholderData: (previousBook) => previousBook ?? {id: 123, title: "Default Book"},
});
}

function useBookTitle() {
const {data: book} = useBook();
return book.title;
}
Shouldn't placeholderData always (synchronously, without loading) stand in for data while loading/fetching/intializing/etc? If not, how can I achieve this? In other words, how can I seed this particular query observer with a known value? (In practice, the above code does not error as far as I've tested. I also tried initialData, but that seems to override placeholderData with flashes back to the inital value -- I want the use-the-previous-thing behavior)
5 Replies
other-emerald
other-emerald6mo ago
If a query errors, placeholderData won't be there anymore. That's why it doesn't do type narrowing
other-emerald
other-emerald6mo ago
Placeholder and Initial Data in React Query
Learn about the different possibilities to avoid loading spinners in React Query.
like-gold
like-goldOP6mo ago
Thank you!
conscious-sapphire
conscious-sapphire3mo ago
Suppose the queryFn returns an array, and suppose an empty array is acceptable. Then suppose the query has placeholderData: (prev) => prev ?? []. Then suppose the query also has throwOnError: true. In that case, it seems that data will always have a value by the time it is read during component render. Is that accurate? If so, is there a way to convince TypeScript that this is true? (...Other than by non-null assertion.)
other-emerald
other-emerald3mo ago
no, not possible. best to use suspense if you want that because it guarantees that data is defined

Did you find this page helpful?