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

React中onClick事件触发自定义Hook方法及无效调用报错解决

问题根因

你对自定义Hook的使用规则存在认知偏差,同时代码有多处不符合规范的问题:

  • React 明确要求自定义Hook只能在函数组件的顶层作用域调用,不能直接在事件回调、循环、条件判断中执行
  • 你当前写的sendEmail本质是普通异步工具函数,不是符合规范的自定义Hook(React 要求自定义Hook命名必须以use开头,比如useSendEmail)
  • 报错的核心原因是要么你没贴全代码、sendEmail内部实际调用了React内置Hook,要么项目的Hook检测规则把该函数误判为自定义Hook,检测到你在回调里调用就抛出了错误
修复方案

方案1:直接作为普通工具函数使用(最适配你的场景)

你的sendEmail没有用到任何React内置Hook,完全不需要封装成自定义Hook,直接调整代码即可解决报错:

  1. 修正customHook.ts的未定义变量问题,保持普通函数导出:
// 你之前的mail变量未定义,此处补充默认配置,可根据业务调整
interface MailConfig {
  subject: string;
  body: string;
}
const defaultMail: MailConfig = {
  subject: "咨询反馈",
  body: "感谢您的联系,我们会尽快回复"
}

async function sendEmail(userName: string, userEmail: string, userPhone: string, mail: MailConfig = defaultMail) {
  const mailToUser = {
    to: userEmail,
    subject: mail.subject,
    body: mail.body,
  };

  await fetch(`/api/sendEmail`, {
    method: `POST`,
    headers: { 'Content-Type': `application/json` },
    body: JSON.stringify(mailToUser),
  });
  
  console.log(mailToUser);
}

export default sendEmail;
  1. 修正contact.tsx的语法错误、导入路径,补充异常捕获:
// 调整为你实际的customHook.ts存放路径,比如src/utils/customHook
import sendEmail from 'src/utils/customHook'

// 之前的组件定义少了箭头函数的=>,此处修正
export const Contact = (props:any) => {
  const userName = `Name`;
  const userEmail = `email`;
  const userPhone = `333333333`;

  const handleClick = async () => {
    try {
      await sendEmail(userName, userEmail, userPhone)
      alert("邮件发送成功")
    } catch (err) {
      console.error("邮件发送失败", err)
      alert("邮件发送失败,请稍后重试")
    }
  }

  return (
    <button onClick={handleClick}>Contact</button>
  )
}

方案2:封装为规范自定义Hook(需要关联组件状态时使用)

如果后续需要在发送逻辑中关联加载状态、错误提示等组件状态,可以封装为标准自定义Hook使用:

  1. 调整customHook.ts为符合规范的自定义Hook:
import { useState } from "react"

interface MailConfig {
  subject: string;
  body: string;
}
const defaultMail: MailConfig = {
  subject: "咨询反馈",
  body: "感谢您的联系,我们会尽快回复"
}

// 自定义Hook必须以use开头命名
const useSendEmail = () => {
  // 仅在Hook顶层调用React内置Hook
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<Error | null>(null)

  // 将触发发送的逻辑作为函数返回,供组件在回调中调用
  const send = async (userName: string, userEmail: string, userPhone: string, mail: MailConfig = defaultMail) => {
    setLoading(true)
    setError(null)
    try {
      const mailToUser = {
        to: userEmail,
        subject: mail.subject,
        body: mail.body,
      };
      await fetch(`/api/sendEmail`, {
        method: `POST`,
        headers: { 'Content-Type': `application/json` },
        body: JSON.stringify(mailToUser),
      });
      console.log(mailToUser);
    } catch (err) {
      setError(err as Error)
      throw err
    } finally {
      setLoading(false)
    }
  }

  return { send, loading, error }
}

export default useSendEmail;
  1. 组件中按规则使用自定义Hook:
import useSendEmail from 'src/utils/customHook'

export const Contact = (props:any) => {
  const userName = `Name`;
  const userEmail = `email`;
  const userPhone = `333333333`;
  // 在组件顶层调用自定义Hook,拿到发送方法和状态
  const { send: sendEmail, loading, error } = useSendEmail()

  const handleClick = async () => {
    try {
      await sendEmail(userName, userEmail, userPhone)
      alert("邮件发送成功")
    } catch (err) {
      console.error("邮件发送失败", err)
      alert("邮件发送失败,请稍后重试")
    }
  }

  return (
    <>
      <button onClick={handleClick} disabled={loading}>
        {loading ? "发送中..." : "Contact"}
      </button>
      {error && <p style={{color: 'red'}}>发送失败:{error.message}</p>}
    </>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 20:36:03