Vue3中使用@tanstack/vue-query执行PUT/PATCH操作的报错及正确实现方式
解决@tanstack/vue-query中PUT/PATCH操作的类型错误问题
你的类型错误核心源于mutation参数类型未明确定义,以及mutationFn的参数解构方式不匹配。以下是标准的实现步骤,附带完整代码示例:
1. 先定义清晰的TypeScript类型
给产品和更新请求参数明确类型,避免TS自动推导出错:
// types/product.ts export interface Product { id: number; name: string; price: number; // 补充你的其他产品字段 } // 更新请求的参数类型:必须包含产品ID和待更新的部分数据 export interface UpdateProductParams { id: number; data: Partial<Product>; }
2. 修正services/product.ts中的接口方法
确保update方法接收正确的参数类型,并返回对应Promise:
// services/product.ts import type { Product, UpdateProductParams } from '@/types/product'; // 获取单个产品详情 export const fetchProduct = async (id: number): Promise<Product> => { const res = await fetch(`/api/products/${id}`); if (!res.ok) throw new Error('获取产品失败'); return res.json(); }; // 产品更新(PUT/PATCH通用,根据后端接口调整method) export const updateProduct = async ({ id, data }: UpdateProductParams): Promise<Product> => { const res = await fetch(`/api/products/${id}`, { method: 'PUT', // 后端用PATCH就改成'PATCH' headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!res.ok) throw new Error('更新产品失败'); return res.json(); };
3. 在edit.vue中正确使用useMutation
组件里确保useMutation的参数传递和类型完全匹配:
<script setup lang="ts"> import { useRoute } from 'vue-router'; import { useQuery, useMutation, useQueryClient } from '@tanstack/vue-query'; import { fetchProduct, updateProduct } from '@/services/product'; import type { Product, UpdateProductParams } from '@/types/product'; const route = useRoute(); const productId = Number(route.params.id); const queryClient = useQueryClient(); // 获取产品数据绑定到表单 const { data: product } = useQuery({ queryKey: ['product', productId], queryFn: () => fetchProduct(productId), }); // 定义更新mutation const updateMutation = useMutation({ mutationFn: (params: UpdateProductParams) => updateProduct(params), // 更新成功后让对应缓存失效,自动拉取最新数据 onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['product', productId] }); // 可添加路由跳转,比如回到产品列表页 }, onError: (err) => { console.error('更新失败:', err.message); }, }); // 表单提交逻辑 const handleSubmit = () => { if (!product.value) return; // formData为表单收集的更新数据(用v-model绑定的对象) const formData = { name: product.value.name, price: product.value.price, // 其他修改后的字段 }; // 调用mutate必须传入符合UpdateProductParams类型的参数 updateMutation.mutate({ id: productId, data: formData }); }; </script> <template> <form @submit.prevent="handleSubmit"> <input v-model="product?.name" placeholder="产品名称" /> <input v-model.number="product?.price" placeholder="产品价格" type="number" /> <button type="submit" :disabled="updateMutation.isPending"> {{ updateMutation.isPending ? '更新中...' : '保存修改' }} </button> </form> </template>
关键注意点
- mutation参数必须是单一值:useMutation的mutate方法只接受一个参数,所以需要传递多个值(比如id和data)时,必须包装成一个对象,这是你之前解构提示“属性不存在”的核心原因——你可能尝试给mutationFn传两个独立参数,而非一个包含两个属性的对象。
- 可选的泛型指定:如果TS自动推导不够准确,可手动给useMutation指定泛型,明确返回值、错误、参数类型:
const updateMutation = useMutation<Product, Error, UpdateProductParams>({ // ...配置内容 }); - 缓存更新:更新成功后调用
invalidateQueries让对应缓存失效,确保页面展示最新数据。
内容的提问来源于stack exchange,提问作者psudo
相关产品推荐
相关产品推荐

