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

使用TanStack React Query编写POST函数时遇TypeScript错误求助

问题分析

报错Type '(title: any) => Promise<AxiosResponse<any, any>>' has no properties in common with type 'UseMutationOptions<unknown, Error, void, unknown>'的核心原因有两个:

  1. 原代码中useMutation调用存在语法错误,导致TypeScript无法正确解析参数结构;
  2. 未显式指定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_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:34:59