Replies: 4 comments 16 replies
-
This totally makes sense. About the differences:
I not entirely sure about the implementation of this, but to inject the placeholderData: (previousData, previousQuery) => {
return previousQuery.dataUpdatedAt > myTimestamp ? previousData : { myNewPlaceholder: 'foo' };
} or even placeholderData: (previousQuery) => {
return previousQuery.dataUpdatedAt > myTimestamp ? previousQuery.data : { myNewPlaceholder: 'foo' };
} Not sure if this is feasible though. |
Beta Was this translation helpful? Give feedback.
-
I don't use placeholder data, let me talk about my business scenario: When I am on page n, if the data of this page is pre-fetched by me, or already exists in the cache, then I hope that loading will not be displayed, |
Beta Was this translation helpful? Give feedback.
-
about isPreviousData mean use cacheData ? if no, i think need add a flag const Demo = () => {
const [page, setPage] = useState(1)
const params = {
username: '',
page: page,
}
const { isFetching, data, isPreviousData } = useQuery({
queryKey: ['post', params],
queryFn: () => axios.post('post', params),
keepPreviousData: true,
})
// if it is first fetching some page,show loading, else hide loading
if (isPreviousData && isFetching) {
return 'loading'
}
return (
<>
<div>{data}</div>
<button onClick={() => setPage(page - 1)}> - </button>
{page}
<button onClick={() => setPage(page + 1)}> + </button>
</>
)
} |
Beta Was this translation helpful? Give feedback.
-
Sorry for bike-shedding! TL;DR I think the new Now that When I hear "placeholder", I think about static, made-up data. The field now has two different use cases. (For anyone wondering, the second use case still works totally fine with I just think that the naming now could be confusing. But the existing With that in mind, we could rename like so to better represent their usage:
|
Beta Was this translation helpful? Give feedback.
-
Motivation
The API surface of TanStack query is quite large, and we have a couple of things that do seemingly similar things as different config options.
keepPreviousData
andplaceholderData
are two of those that are very similar:The interesting thing is further: You cannot show both previousData and placeholderData at the same time. We also return two flags from useQuery:
isPreviousData
andisPlaceholderData
. Again, you cannot be both things at the same time, because only "one data" can be shown.If you supply both things, it is an implementation detail about what takes precedence:
if we show the first post, we would of course see the placeholderData. If we would then switch the queryKey and transition to the second post, we would likely still see data from the first post (due to
keepPreviousData
). We could however also argue thatplaceholderData
takes precedence and we show this one. It is not clear from the api what binds "stronger", and it could also be kind of an impossible state that you have placeholder and previous data at the same time.Proposal
We could treat
previousData
asplaceholderData
by allowing theplaceholderData
function syntax to pass the data from previous queries (if one exists) in as parameter. The above example would become:Please note: The
placeholderData
function syntax exists today, it just doesn't receive any parameters.Advantages
keepPreviousData
takes precedence overplaceholderData
. Or, you had to try it out to see what happensThis might also be interesting for infinite queries (e.g. a todo list with filters), where you know that the new query will only have one page, so you can decide to only keep one page of the old query (e.g. to make scrollbars disappear and re-align content earlier):
Differences
There are a couple of slight differences in implementation between the two:
placeholderData
will always put you intosuccess
state, whilekeepPreviousData
will give you the status of the previous query. That status could beerror
if we have data fetched successfully and then got a background refetch error. However, the error itself is not shared. This doesn't seem quite right in any case...keepPreviousData
will give you thedataUpdatedAt
timestamp of the previous data, while withplaceholderData
,dataUpdatedAt
will stay at0
. This might be annoying if you want to show that timestamp continuously on screen.Both of these things are edge case differences and largely irrelevant. If we treat previousData like placeholderData, I would argue to keep things aligned with the current implementation of
placeholderData
Drawbacks
keepPreviousData
, you would need:dataUpdatedAt
from previous queriesAlternatives considered
We could introduce a Symbol for
keepPreviousData
that users could import and pass toplaceholderData
to get the same behaviour as now:this also reads nice and still combines the api into one field. We could do this instead of the function syntax, however, it has the distinct drawback that you cannot do what you can do now, which is: show a placeholder for the first query, and then when the key changes, show data from the previous query (see the initial example).
We could however do this additionally to avoid users having to pass
placeholderData: previousData => previousData
. In that case, instead of a symbol, we could also export an identity function.Unknowns
There is quite some code for
useQueries
that make surekeepPreviousData
works (somewhat). In an Array of dynamic length, it is not easy to find out which the "previous" query was. I'm not sure if we can (and should) keep the behaviour there, or if we would just always passundefined
to theplaceholderData
function.Closing thoughts
keepPreviousData
might become less relevant as we move more towardssuspense
andstarTransition
. By wrapping the state setting that changes the query key intostartTransition
, you can achieve the same behaviour askeepPreviousData
. You can see that in the suspense example. So, moving away from a dedicated flag might be a good thing, and the more verbose syntax to achieve what we have today might not be so relevant in the grand scheme...Beta Was this translation helpful? Give feedback.
All reactions