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
相关产品推荐
相关产品推荐

