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

React Query中如何高效实现深层嵌套数据的乐观更新?

优化React Query乐观更新的实现

你当前的乐观更新代码因嵌套数据结构导致逻辑冗余复杂,可从逻辑抽离、效率优化、类型安全三个方向简化:

1. 抽离状态更新逻辑为独立函数

把修改待办完成状态的逻辑从onMutate中拆分出来,让mutation配置更简洁,同时方便后续复用或修改:

// 抽离的待办状态更新函数
const updateTodoChecked = (
  prev: typeof data,
  todoId: number,
  checked: boolean
): typeof data => {
  return {
    ...prev,
    lists: prev.lists.map(list => {
      // 判断当前列表是否包含目标待办
      const hasTargetTodo = list.todoOrder.includes(todoId);
      if (!hasTargetTodo) return list;

      // 更新目标待办的状态
      return {
        ...list,
        todos: list.todos.map(todo =>
          todo.id === todoId ? { ...todo, checked } : todo
        )
      };
    })
  };
};

改造后的mutation代码:

const mutation = useMutation(
  ({ todoId, checked }: { todoId: number; checked: boolean }) => 
    editTodo({ todoId, checked }),
  {
    onMutate: async (variables) => {
      await queryClient.cancelQueries('listCollection');
      const previousState = queryClient.getQueryData('listCollection');
      
      // 调用抽离的更新函数修改状态
      queryClient.setQueryData('listCollection', prev => 
        prev ? updateTodoChecked(prev, variables.todoId, variables.checked) : prev
      );

      return { previousState };
    },
    onError: (_, __, context) => {
      // 错误回滚时直接恢复之前的状态
      if (context?.previousState) {
        queryClient.setQueryData('listCollection', context.previousState);
      }
    },
    onSuccess: () => {
      queryClient.invalidateQueries('listCollection');
    }
  }
);

2. 优化数据查找效率

当前遍历所有列表判断是否包含目标待办的方式可以优化,提前维护一个待办ID到所属列表的映射,减少遍历次数:

// 在组件中用useMemo维护映射,避免重复计算
const todoToListMap = useMemo(() => {
  const map = new Map<number, IList>();
  data?.lists.forEach(list => {
    list.todoOrder.forEach(todoId => map.set(todoId, list));
  });
  return map;
}, [data]);

更新抽离的函数:

const updateTodoChecked = (
  prev: typeof data,
  todoId: number,
  checked: boolean,
  todoToListMap: Map<number, IList>
): typeof data => {
  const targetList = todoToListMap.get(todoId);
  if (!targetList) return prev;

  return {
    ...prev,
    lists: prev.lists.map(list => {
      if (list.id !== targetList.id) return list;
      
      return {
        ...list,
        todos: list.todos.map(todo =>
          todo.id === todoId ? { ...todo, checked } : todo
        )
      };
    })
  };
};

调用时传入映射:

queryClient.setQueryData('listCollection', prev => 
  prev ? updateTodoChecked(prev, variables.todoId, variables.checked, todoToListMap) : prev
);

3. 强化类型安全

去掉代码中的any类型,利用TypeScript的类型推导确保所有状态更新操作的类型正确性,避免运行时错误。比如prev参数直接使用typeof data约束类型,无需手动标注any。

其他复用建议

对于添加待办、删除待办等其他mutation的乐观更新,也可采用同样模式:抽离独立的状态更新函数,保持代码风格一致,降低维护成本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 16:46:14