使用TanStack React Query编写POST函数时遇TypeScript错误求助
问题分析
报错Type '(title: any) => Promise<AxiosResponse<any, any>>' has no properties in common with type 'UseMutationOptions<unknown, Error, void, unknown>'的核心原因有两个:
- 原代码中
useMutation调用存在语法错误,导致TypeScript无法正确解析参数结构; - 未显式指定
useMutation的泛型参数,加上mutate调用逻辑缺失,引发类型推断混乱。
解决方案
1. 修复基础语法错误
原代码中第13行的箭头函数末尾多了分号,且useMutation的括号未闭合,这是最直接的语法问题:
// 错误写法 const { mutate } = useMutation( async (title) => await axios.post("/api/posts/addPost", { title }); // 多了分号,且括号未闭合 ); // 正确写法 const { mutate } = useMutation( async (title: string) => await axios.post("/api/posts/addPost", { title }) );
2. 完善表单提交逻辑,调用mutate
原表单没有绑定onSubmit事件,导致mutate从未被触发,同时需要在提交时处理按钮状态、输入验证:
"use client"; import { useState } from "react"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import axios from "axios"; import React from "react"; export default function CreatePost() { const [title, setTitle] = useState(""); const [isDisabled, setIsDisabled] = useState(false); const queryClient = useQueryClient(); // 显式指定泛型参数,增强类型安全 const { mutate, isLoading } = useMutation({ mutationFn: async (title: string) => { return await axios.post("/api/posts/addPost", { title }); }, onSuccess: () => { // 可选:提交成功后更新缓存,比如刷新帖子列表 queryClient.invalidateQueries({ queryKey: ["posts"] }); setTitle(""); // 清空输入框 }, onSettled: () => { setIsDisabled(false); // 请求结束后恢复按钮状态 } }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!title.trim()) return; // 空内容不提交 setIsDisabled(true); mutate(title); // 传入title触发mutation }; return ( <form className="bg-white my-8 p-8 rounded-md" onSubmit={handleSubmit}> <div className="flex flex-col my-4"> <textarea onChange={(e) => setTitle(e.target.value)} name="title" value={title} placeholder="What's on your mind?" className="p-4 text-lg rounded-md my-2 bg-gray-200" maxLength={300} ></textarea> </div> <div className="flex items-center justify-between gap-2"> <p className={`font-bold text-sm ${title.length > 300 ? "text-red-700" : "text-gray-700"}`} >{`${title.length}/300`}</p> <button disabled={isDisabled || isLoading} // 结合内置isLoading避免重复提交 className="text-white text-sm px-6 py-2 rounded-xl bg-teal-600 disabled:opacity-25" type="submit" > Create a Post </button> </div> </form> ); }
3. 抽离useAddPost的正确写法
如果要单独抽离自定义hook,需确保泛型参数正确传递,明确类型约束:
import { useMutation, UseMutationResult } from '@tanstack/react-query'; import axios, { AxiosResponse } from 'axios'; // 定义请求参数和响应类型(根据实际API调整) type AddPostParams = { title: string }; type AddPostResponse = { id: string; title: string }; const useAddPost = (): UseMutationResult<AxiosResponse<AddPostResponse>, Error, AddPostParams> => { return useMutation({ mutationFn: async ({ title }: AddPostParams) => { return await axios.post<AddPostResponse>("/api/posts/addPost", { title }); }, onSuccess: (data) => { console.log('Post added successfully:', data); }, onError: (error) => { console.error('Error adding post:', error); } }); }; export default useAddPost;
在组件中使用抽离的hook:
import useAddPost from './hooks/useAddPost'; export default function CreatePost() { const [title, setTitle] = useState(""); const [isDisabled, setIsDisabled] = useState(false); const { mutate, isLoading } = useAddPost(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!title.trim()) return; setIsDisabled(true); mutate({ title }); // 传递符合类型约束的参数 }; // 其余代码与上述组件示例一致 }
关键注意点
- 确保
useMutation的参数结构正确:推荐传递包含mutationFn的配置对象,写法更清晰易维护; - 显式指定泛型参数能大幅提升TypeScript的类型推断准确性,避免无意义的类型错误;
- 表单提交必须调用
e.preventDefault()阻止默认跳转,并在验证通过后调用mutate传入参数; - 结合React Query内置的
isLoading状态和自定义isDisabled控制按钮状态,避免重复提交。
内容的提问来源于stack exchange,提问作者ZingZing_
相关产品推荐
相关产品推荐

