Add some more clarity to the RQ docs
This commit is contained in:
@@ -431,16 +431,30 @@ yarn intl:compile # Compile translations for runtime
|
|||||||
// src/state/queries/profile.ts
|
// src/state/queries/profile.ts
|
||||||
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
// Query key pattern
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
const RQKEY_ROOT = 'profile'
|
|
||||||
export const RQKEY = (did: string) => [RQKEY_ROOT, did]
|
|
||||||
|
|
||||||
// Query hook
|
/*
|
||||||
|
* Query key name should match the query hook name for consistency
|
||||||
|
*/
|
||||||
|
const profileQueryKeyRoot = 'profile'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use object params and createQueryKey helper for better readability and to
|
||||||
|
* avoid bugs with parameter order or types.
|
||||||
|
*/
|
||||||
|
export const createProfileQueryKey = (args: {did: string}) =>
|
||||||
|
createQueryKey(profileQueryKeyRoot, args)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query hook should be named use[Name]Query, where [Name] describes the data
|
||||||
|
* being fetched. This is not a strict requirement, but it's a helpful
|
||||||
|
* convention for discoverability
|
||||||
|
*/
|
||||||
export function useProfileQuery({did}: {did: string}) {
|
export function useProfileQuery({did}: {did: string}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: RQKEY(did),
|
queryKey: createProfileQueryKey({did}),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfile({actor: did})
|
const res = await agent.getProfile({actor: did})
|
||||||
return res.data
|
return res.data
|
||||||
@@ -450,8 +464,12 @@ export function useProfileQuery({did}: {did: string}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation hook
|
/*
|
||||||
export function useUpdateProfile() {
|
* Mutation hook should match the name of the query hook, but with "Mutation"
|
||||||
|
* suffix. This is not a strict requirement, but it's a helpful convention for
|
||||||
|
* discoverability and consistency.
|
||||||
|
*/
|
||||||
|
export function useProfileMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
@@ -459,7 +477,9 @@ export function useUpdateProfile() {
|
|||||||
// Update logic
|
// Update logic
|
||||||
},
|
},
|
||||||
onSuccess: (_, variables) => {
|
onSuccess: (_, variables) => {
|
||||||
queryClient.invalidateQueries({queryKey: RQKEY(variables.did)})
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: createProfileQueryKey({did: variables.did}),
|
||||||
|
})
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isNetworkError(error)) {
|
if (isNetworkError(error)) {
|
||||||
@@ -473,6 +493,24 @@ export function useUpdateProfile() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If cache mutation is needed, include specific interfaces for the specific
|
||||||
|
* mutations you require adjacent to the source queries. Naming should be
|
||||||
|
* descriptive of the mutation's purpose, e.g. use[Name]CacheMutation. This is
|
||||||
|
* not a strict requirement, but it's a helpful convention for discoverability
|
||||||
|
* and consistency.
|
||||||
|
*/
|
||||||
|
export function useProfileCacheMutation() {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return (data: Partial<Profile>) => {
|
||||||
|
queryClient.setQueryData(createProfileQueryKey({did: data.did}), oldData => {
|
||||||
|
if (!oldData) return oldData
|
||||||
|
return {...oldData, ...data}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Stale Time Constants** (from `src/state/queries/index.ts`):
|
**Stale Time Constants** (from `src/state/queries/index.ts`):
|
||||||
@@ -491,7 +529,7 @@ export function useDraftsQuery() {
|
|||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
return useInfiniteQuery({
|
return useInfiniteQuery({
|
||||||
queryKey: ['drafts'],
|
queryKey: createQueryKey('drafts'),
|
||||||
queryFn: async ({pageParam}) => {
|
queryFn: async ({pageParam}) => {
|
||||||
const res = await agent.app.bsky.draft.getDrafts({cursor: pageParam})
|
const res = await agent.app.bsky.draft.getDrafts({cursor: pageParam})
|
||||||
return res.data
|
return res.data
|
||||||
|
|||||||
@@ -14,6 +14,30 @@ import {
|
|||||||
|
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to ensure consistent query keys and key ordering
|
||||||
|
*/
|
||||||
|
export function createQueryKey(root: string): readonly [string]
|
||||||
|
export function createQueryKey<T extends Record<string, unknown>>(
|
||||||
|
root: string,
|
||||||
|
args: T,
|
||||||
|
): readonly [string, T]
|
||||||
|
export function createQueryKey<T extends Record<string, unknown>>(
|
||||||
|
/**
|
||||||
|
* The query key root. All queries must have a root.
|
||||||
|
*/
|
||||||
|
root: string,
|
||||||
|
/**
|
||||||
|
* Any arguments the query depends on, and if changed, should result in the query being refetched.
|
||||||
|
*/
|
||||||
|
args?: T,
|
||||||
|
) {
|
||||||
|
if (args === undefined) {
|
||||||
|
return [root] as const
|
||||||
|
}
|
||||||
|
return [root, args] as const
|
||||||
|
}
|
||||||
|
|
||||||
export async function truncateAndInvalidate<T = any>(
|
export async function truncateAndInvalidate<T = any>(
|
||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
queryKey: QueryKey,
|
queryKey: QueryKey,
|
||||||
|
|||||||
Reference in New Issue
Block a user