You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Query:用列表查询结果设置单个项缓存是否可行?

问题解答

这种做法不仅不是反模式,反而属于React Query官方推荐的「数据规范化」实践,刚好能解决你现在遇到的多列表同步更新复杂低效的问题。

为什么这是合理的

  • React Query的缓存系统支持细粒度操作,你通过setQueryData把列表里的单个Todo存入['todo', todo.id]独立缓存键,本质是把扁平化的列表数据拆成单条实体,和后端REST/GraphQL的实体设计思路一致。
  • 这种方式让单个Todo组件直接依赖对应id的缓存,不用关心数据来自哪个列表查询,彻底避免了跨['my-todo-list']、['all-todo-list']等多个列表重复更新的麻烦。

现有代码的优化点

你当前在useTodos的组件渲染逻辑里循环调用setQueryData,每次组件渲染都会执行,建议把这个逻辑移到useQuery的onSuccess回调中,只在列表数据成功获取时更新一次,避免不必要的重复操作:

export const useTodos = () => {
  const queryClient = useQueryClient()
  const todoQuery = useQuery(
    ['todo-list'],
    fetchTodos,
    {
      onSuccess: (data) => {
        data.todos?.forEach((todo) => {
          queryClient.setQueryData(['todo', todo.id], todo)
        })
      }
    }
  )

  return todoQuery
}

另外,对于useTodoById,可以设置initialData从已有列表缓存中读取数据,避免列表已经加载完成后,单个Todo组件还显示loading状态:

export const useTodoById = (id) => {
  const queryClient = useQueryClient()
  return useQuery(
    ['todo', id],
    () => fetchTodoById(id),
    {
      staleTime: 10 * 60 * 1000, // 10分钟
      initialData: () => {
        // 优先从已有的列表缓存中查找对应Todo作为初始数据
        return queryClient.getQueryData(['todo-list'])?.todos?.find(todo => todo.id === id)
        || queryClient.getQueryData(['my-todo-list'])?.todos?.find(todo => todo.id === id)
      }
    }
  )
}

突变更新的优化思路

当标记Todo为“已完成”时,你只需要更新['todo', id]的缓存,再按需让相关列表查询失效即可,不用逐个更新所有列表:

const markTodoAsDone = async (id) => {
  const queryClient = useQueryClient()
  // 乐观更新单个Todo
  queryClient.setQueryData(['todo', id], old => ({...old, completed: true}))
  try {
    await updateTodoApi(id, {completed: true})
  } catch (err) {
    // 更新失败回滚缓存
    queryClient.setQueryData(['todo', id], old => ({...old, completed: false}))
    throw err
  }
  // 让所有Todo列表查询变为stale,下次渲染时自动刷新(根据业务需求选择是否开启)
  queryClient.invalidateQueries(['todo-list'])
  queryClient.invalidateQueries(['my-todo-list'])
}

内容的提问来源于stack exchange,提问作者Jester2007

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 03:52:15