Skip to content

Commit

Permalink
refactor!: adapt status
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `status` property, `isPending`, `isFetching` are now a
bit different.
  • Loading branch information
posva committed Feb 4, 2024
1 parent 1150201 commit 2d5625c
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 21 deletions.
17 changes: 12 additions & 5 deletions src/data-fetching-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ import type {
import { type _MaybeArray, stringifyFlatObject, _JSONPrimitive } from './utils'
import { EntryNodeKey, TreeMapNode } from './tree-map'

export type UseQueryStatus = 'pending' | 'error' | 'success'
/**
* The status of the request.
* - `pending`: initial state
* - `loading`: anytime a request is being made
* - `error`: when the last request failed
* - `success`: when the last request succeeded
*/
export type UseQueryStatus = 'pending' | 'loading' | 'error' | 'success'

/**
* Raw data of a query entry. Can be serialized from the server and used to hydrate the store.
Expand All @@ -44,9 +51,9 @@ export class UseQueryEntry<TResult = unknown, TError = any> {
data: Ref<TResult | undefined>
error: ShallowRef<TError | null>
isPending: ComputedRef<boolean> = computed(
() => this.status.value === 'pending'
() => this.data.value === undefined
)
isFetching: ShallowRef<boolean> = shallowRef(false)
isFetching = computed(() => this.status.value === 'loading')
status: ShallowRef<UseQueryStatus>
when: number
pending: null | {
Expand Down Expand Up @@ -116,7 +123,7 @@ export class UseQueryEntry<TResult = unknown, TError = any> {
}

console.log('🔄 refetching', this.options!.key)
this.isFetching.value = true
this.status.value = 'loading'
// will become this.previous once fetched
const nextPrevious = {
when: 0,
Expand Down Expand Up @@ -148,7 +155,6 @@ export class UseQueryEntry<TResult = unknown, TError = any> {
this.pending = null
nextPrevious.when = Date.now()
this.previous = nextPrevious
this.isFetching.value = false
}
}),
when: Date.now(),
Expand Down Expand Up @@ -261,6 +267,7 @@ export const useDataFetchingStore = defineStore('PiniaColada', () => {
entry.error.value = null
}

// TODO: find a way to make it possible to prefetch. Right now we need the actual options of the query
function prefetch(key: UseQueryKey[]) {
const entry = entryRegistry.get(key.map(stringifyFlatObject))
if (!entry) {
Expand Down
47 changes: 36 additions & 11 deletions src/use-mutation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { computed, ref, type ComputedRef, shallowRef } from 'vue'
import { useDataFetchingStore } from './data-fetching-store'
import { UseQueryStatus, useDataFetchingStore } from './data-fetching-store'
import { type UseQueryKey } from './use-query'
import { type _MaybeArray, toArray } from './utils'

Expand Down Expand Up @@ -30,11 +30,37 @@ export interface UseMutationReturn<
TParams extends readonly unknown[] = readonly [],
TError = Error,
> {
/**
* The result of the mutation. `undefined` if the mutation has not been called yet.
*/
data: ComputedRef<TResult | undefined>

/**
* The error of the mutation. `null` if the mutation has not been called yet or if it was successful.
*/
error: ComputedRef<TError | null>
isPending: ComputedRef<boolean>

/**
* Whether the mutation is currently executing.
*/
isLoading: ComputedRef<boolean>

/**
* The status of the mutation.
* @see {@link UseQueryStatus}
*/
status: ComputedRef<UseQueryStatus>

/**
* Calls the mutation and returns a promise with the result.
*
* @param params - parameters to pass to the mutation
*/
mutate: (...params: TParams) => Promise<TResult>

/**
* Resets the state of the mutation to its initial state.
*/
reset: () => void
}

Expand All @@ -47,21 +73,22 @@ export function useMutation<
): UseMutationReturn<TResult, TParams, TError> {
const store = useDataFetchingStore()

const isPending = ref(false)
const status = shallowRef<UseQueryStatus>('pending')
const data = shallowRef<TResult>()
const error = shallowRef<TError | null>(null)

// a pending promise allows us to discard previous ongoing requests
let pendingPromise: Promise<TResult> | null = null
function mutate(...args: TParams) {
isPending.value = true
error.value = null
status.value = 'loading'

const promise = (pendingPromise = options
.mutation(...args)
.then((_data) => {
if (pendingPromise === promise) {
data.value = _data
error.value = null
status.value = 'success'
if (options.keys) {
const keys = (
typeof options.keys === 'function'
Expand All @@ -78,13 +105,9 @@ export function useMutation<
.catch((_error) => {
if (pendingPromise === promise) {
error.value = _error
status.value = 'error'
}
throw _error
})
.finally(() => {
if (pendingPromise === promise) {
isPending.value = false
}
}))

return promise
Expand All @@ -93,11 +116,13 @@ export function useMutation<
function reset() {
data.value = undefined
error.value = null
status.value = 'pending'
}

const mutationReturn = {
data: computed(() => data.value),
isPending: computed(() => isPending.value),
isLoading: computed(() => status.value === 'loading'),
status: computed(() => status.value),
error: computed(() => error.value),
mutate,
reset,
Expand Down
1 change: 0 additions & 1 deletion src/use-query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ describe('useQuery', () => {
it('exposes a status state', async () => {
const { wrapper } = mountSimple()

expect(wrapper.vm.status).toBe('pending')
await runTimers()
expect(wrapper.vm.status).toBe('success')
})
Expand Down
7 changes: 3 additions & 4 deletions src/use-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ export interface UseQueryReturn<TResult = unknown, TError = Error> {
isFetching: ShallowRef<boolean>

/**
* The status of the request. `pending` indicates that no request has been made yet and there is no cached data to
* display (`data.value = undefined`). `error` indicates that the last request failed. `success` indicates that the
* last request succeeded.
* The status of the query.
* @see {@link UseQueryStatus}
*/
status: ShallowRef<UseQueryStatus>

Expand Down Expand Up @@ -89,7 +88,7 @@ export interface UseQueryOptions<TResult = unknown> {
staleTime?: number

/**
* Time in ms after which, once the data is no longer in used, it will be garbage collected to free resources.
* Time in ms after which, once the data is no longer being used, it will be garbage collected to free resources.
*/
gcTime?: number

Expand Down

0 comments on commit 2d5625c

Please sign in to comment.