Skip to content

Commit

Permalink
feat: allow nullish return in placeholderData
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Sep 27, 2024
1 parent 2b5802a commit 1fae179
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 6 deletions.
4 changes: 3 additions & 1 deletion src/query-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ export interface UseQueryOptions<TResult = unknown, TError = ErrorDefault> {
*/
placeholderData?:
| NoInfer<TResult>
| (<T extends TResult>(previousData: T | undefined) => NoInfer<TResult>)
| (<T extends TResult>(
previousData: T | undefined,
) => NoInfer<TResult> | null | void | undefined)

/**
* Function to type and ensure the `error` property is always an instance of `TError`.
Expand Down
2 changes: 1 addition & 1 deletion src/query-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface UseQueryEntry<TResult = unknown, TError = unknown> {
* A placeholder `data` that is initially shown while the query is loading for the first time. This will also show the
* `status` as `success` until the query finishes loading (no matter the outcome).
*/
placeholderData: TResult | null
placeholderData: TResult | null | undefined | void

/**
* The status of the query.
Expand Down
91 changes: 87 additions & 4 deletions src/use-query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ describe('useQuery', () => {
await flushPromises()
expect(wrapper.vm.isPlaceholderData).toBe(false)
expect(wrapper.vm.data).toBe(42)
expect(wrapper.vm.status).toBe('success')
expect(wrapper.vm.asyncStatus).toBe('idle')
})

it('works with a function', async () => {
Expand All @@ -401,15 +403,96 @@ describe('useQuery', () => {
})

expect(wrapper.vm.data).toBe(24)
expect(wrapper.vm.isPlaceholderData).toBe(true)
await flushPromises()
expect(wrapper.vm.data).toBe(42)
expect(wrapper.vm.isPlaceholderData).toBe(false)
})

it('ignores the placeholderData if it returns a nullish value', async () => {
const { wrapper } = mountSimple({
query: async () => 42,
placeholderData: () => null,
})

expect(wrapper.vm.data).toBe(undefined)
expect(wrapper.vm.isPlaceholderData).toBe(false)
await flushPromises()
expect(wrapper.vm.data).toBe(42)
})

it.todo('ignores the placeholderData if there is already data in the cache')
it.todo('ignores the placeholderData if there is already an error in the cache')
it.todo('ignores the placeholderData if it returns a nullish value')
it('shows even when not enabled', async () => {
const { wrapper } = mountSimple({
query: async () => 42,
placeholderData: 24,
enabled: false,
})

expect(wrapper.vm.data).toBe(24)
expect(wrapper.vm.isPlaceholderData).toBe(true)
await flushPromises()
expect(wrapper.vm.data).toBe(24)
expect(wrapper.vm.isPlaceholderData).toBe(true)
})

it('ignores the placeholderData if there is already data in the cache', async () => {
const pinia = createPinia()
const options = {
key: ['id'],
query: async () => 42,
placeholderData: 24,
} satisfies UseQueryOptions
const [w1] = mountSimple(options, { plugins: [pinia] })

it.todo('calls the placeholderData function with the previous data if the entry key changes')
await flushPromises()
// ensure data is there
expect(w1.vm.data).toBe(42)

const [w2] = mountSimple(options, { plugins: [pinia] })
// placeholder is not used
expect(w2.vm.data).toBe(42)
expect(w2.vm.isPlaceholderData).toBe(false)
})

it('ignores the placeholderData if there is already an error in the cache', async () => {
const pinia = createPinia()
const options: UseQueryOptions<number> = {
key: ['id'],
query: async () => {
throw new Error('fail')
},
placeholderData: 24,
}
const [w1] = mountSimple(options, { plugins: [pinia] })

await flushPromises()
// ensure the error
expect(w1.vm.error).toEqual(new Error('fail'))

const [w2] = mountSimple(options, { plugins: [pinia] })
// placeholder is not used
expect(w2.vm.data).toBe(undefined)
expect(w2.vm.isPlaceholderData).toBe(false)
expect(w2.vm.error).toEqual(new Error('fail'))
})

it('calls the placeholderData function with the previous data if the entry key changes', async () => {
const key = ref(1)
const placeholderData = vi.fn(() => 24)
const { wrapper } = mountSimple({
key: () => [key.value],
query: async () => 42,
placeholderData,
})

await flushPromises()

key.value = 2
await nextTick()
expect(placeholderData).toHaveBeenCalledTimes(2)
expect(placeholderData).toHaveBeenCalledWith(42)
expect(wrapper.vm.data).toBe(24)
})
})

describe('refresh data', () => {
Expand Down

0 comments on commit 1fae179

Please sign in to comment.