
配圖源自 Freepik
本文以 V5 版本為例
Query Key
它是由字符串、(可嵌套)對(duì)象、或兩者兼具組成的數(shù)組。
順序
數(shù)組的順序很重要
// 以下 Query Key 不相同
useQuery({ queryKey: ['todos', status, page] })
useQuery({ queryKey: ['todos', page, status] })
useQuery({ queryKey: ['todos', undefined, page, status] })
對(duì)象的順序不重要
// 以下 Query Key 相同
useQuery({ queryKey: ['todos', { status, page }] })
useQuery({ queryKey: ['todos', { page, status }] })
useQuery({ queryKey: ['todos', { page, status, other: undefined }] })
對(duì)象總是以確定性的 sort 排序:??
/**
* Default query & mutation keys hash function.
* Hashes the value into a stable hash.
*/
export function hashKey(queryKey: QueryKey | MutationKey): string {
return JSON.stringify(queryKey, (_, val) =>
isPlainObject(val)
? Object.keys(val)
.sort()
.reduce((result, key) => {
result[key] = val[key]
return result
}, {} as any)
: val,
)
}
結(jié)構(gòu)化
盡管 Query Key 在整個(gè) Query 中唯一便可使用,但我們可以按一定的顆粒度進(jìn)行劃分。比如:
useQuery({ queryKey: ['todos', 'list', { filters: 'all' }] })
useQuery({ queryKey: ['todos', 'list', { filters: 'done' }] })
useQuery({ queryKey: ['todos', 'detail', 1] })
useQuery({ queryKey: ['todos', 'detail', 2] })
這樣做的好處是,在處理數(shù)據(jù)更新時(shí)更加靈活,或者批量使對(duì)應(yīng)緩存失效:
function useUpdateTitle() {
return useMutation({
mutationFn: updateTitle,
onSuccess: newTodo => {
// 更新單個(gè)數(shù)據(jù)
queryClient.setQueryData(['todos', 'detail', newTodo.id], newTodo)
// 更新列表數(shù)據(jù)
queryClient.setQueriesData(['todos', 'list'], previous =>
previous.map(todo => (todo.id === newTodo.id ? newTodo : todo))
)
// 使查詢列表失效
queryClient.invalidateQueries({queryKey: ['todos', 'list']})
},
})
}
Related link: https://tkdodo.eu/blog/effective-react-query-keys#structure
有時(shí),使用“純對(duì)象”的 Query Key 更好:
function useTodosQuery(filter: string) {
return useQuery({
// queryKey: ["todos", "list", filter],
queryKey: [{scope: 'todos', entity: 'list', filter}],
queryFn: ({queryKey}) => {
// 保不準(zhǔn)下次會(huì)新增什么參數(shù),此時(shí)對(duì)象要優(yōu)于數(shù)組
// const [, , filter] = queryKey;
const {filter} = queryKey
return fetchTodos({filter})
},
})
}
Related Link: https://tkdodo.eu/blog/leveraging-the-query-function-context#object-query-keys
Select
在 useQuery 或 useInfinityQuery 中的 select 會(huì)在每次組件更新時(shí)執(zhí)行,而不是查詢結(jié)果變化時(shí)才執(zhí)行,所以按需使用 useCallback(但如果處理不會(huì)很復(fù)雜,也不需要緩存處理)。