React Query 小记

配图源自 Freepik

原文链接

本文以 V5 版本为例

Query Key

它是由字符串、(可嵌套)对象、或两者兼具组成的数组。

顺序

数组的顺序很重要

// 以下 Query Key 不相同
useQuery({ queryKey: ['todos', status, page] })
useQuery({ queryKey: ['todos', page, status] })
useQuery({ queryKey: ['todos', undefined, page, status] })

对象的顺序不重要

// 以下 Query Key 相同
useQuery({ queryKey: ['todos', { status, page }] })
useQuery({ queryKey: ['todos', { page, status }] })
useQuery({ queryKey: ['todos', { page, status, other: undefined }] })

对象总是以确定性的 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,
  )
}

结构化

尽管 Query Key 在整个 Query 中唯一便可使用,但我们可以按一定的颗粒度进行划分。比如:

useQuery({ queryKey: ['todos', 'list', { filters: 'all' }] })
useQuery({ queryKey: ['todos', 'list', { filters: 'done' }] })
useQuery({ queryKey: ['todos', 'detail', 1] })
useQuery({ queryKey: ['todos', 'detail', 2] })

这样做的好处是,在处理数据更新时更加灵活,或者批量使对应缓存失效:

function useUpdateTitle() {
  return useMutation({
    mutationFn: updateTitle,
    onSuccess: newTodo => {
      // 更新单个数据
      queryClient.setQueryData(['todos', 'detail', newTodo.id], newTodo)

      // 更新列表数据
      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

有时,使用“纯对象”的 Query Key 更好:

function useTodosQuery(filter: string) {
  return useQuery({
    // queryKey: ["todos", "list", filter],
    queryKey: [{scope: 'todos', entity: 'list', filter}],
    queryFn: ({queryKey}) => {
      // 保不准下次会新增什么参数,此时对象要优于数组
      // 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 会在每次组件更新时执行,而不是查询结果变化时才执行,所以按需使用 useCallback(但如果处理不会很复杂,也不需要缓存处理)。

References

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容