React + EmailJS 在onClick方法中重复发送大量邮件及404路由跳转问题排查
嘿,这两个都是React开发里常见的小陷阱,我来帮你一一搞定!
问题1:邮件发送数十封的原因及解决
你现在的按钮onClick写的是this.sendEmail()——注意这里的括号!这会导致组件每次渲染(包括输入字符触发state更新后的重渲染)都会立即调用sendEmail函数,而不是只在点击按钮时执行。所以每输入一个字符就发一封邮件,自然会收到几十封。
解决核心是:把函数引用传递给onClick,而不是立即执行它,同时要确保this的指向正确(类组件的方法默认不会自动绑定组件实例)。这里有三种常用方案:
方式1:在构造函数中绑定this
在constructor里添加绑定代码,一次性搞定this指向:
constructor(){ super() this.state = { fromName:'', message:'', fromEmail:'' } // 绑定this到sendEmail方法 this.sendEmail = this.sendEmail.bind(this) }
然后按钮的onClick改成:
<input type="submit" value="Send Message" className="special" onClick={this.sendEmail}/>
方式2:用箭头函数定义sendEmail
把sendEmail改成类的箭头函数属性,this会自动绑定到组件实例:
sendEmail = () => { const serviceId='...' const templateId='...' const userId='...' emailjs.send(serviceId, templateId, this.state, userId) }
按钮同样用onClick={this.sendEmail}即可。
方式3:在onClick中用箭头函数包裹(简单但不推荐大组件用)
<input type="submit" value="Send Message" className="special" onClick={() => this.sendEmail()}/>
这种方式每次渲染都会创建新的箭头函数,小组件没问题,但大型组件可能影响性能,优先选前两种。
问题2:点击按钮后跳转/#并404的解决
这是因为你的按钮是type="submit",点击后会触发表单的默认提交行为——表单的action="#"会让页面跳转到当前URL的/#位置,而Gatsby的路由系统匹配不到这个路径,所以出现404。
推荐两种解决方案:
方案1:阻止表单默认提交,用onSubmit处理
修改表单标签,添加onSubmit事件,阻止默认行为并调用sendEmail,这更符合表单语义:
<form method="post" action="#" onSubmit={(e) => { e.preventDefault() // 阻止默认提交跳转 this.sendEmail() }}>
然后把按钮的onClick属性去掉,因为表单的submit事件会在点击submit按钮时自动触发。
方案2:把按钮改成type="button"
如果不想用表单的submit事件,直接把按钮类型改成button,这样就不会触发表单默认提交:
<input type="button" value="Send Message" className="special" onClick={this.sendEmail}/>
修改后的完整代码示例
这里用「构造函数绑定this + 表单onSubmit」的方案,你可以直接参考:
import React from 'react' import emailjs from 'emailjs-com' class Main extends React.Component { constructor(){ super() this.state = { fromName:'', message:'', fromEmail:'' } this.sendEmail = this.sendEmail.bind(this) } render() { return ( <div> <article> <form method="post" action="#" onSubmit={(e) => { e.preventDefault() this.sendEmail() }}> <div className="field half first"> <label htmlFor="name">Name</label> <input type="text" name="name" id="name" value={this.state.fromName} onChange={e => this.setState({fromName: e.target.value})}/> </div> <div className="field half"> <label htmlFor="email">Email</label> <input type="text" name="email" id="email" value={this.state.fromEmail} onChange={e => this.setState({fromEmail: e.target.value})}/> </div> <div className="field"> <label htmlFor="message">Message</label> <textarea name="message" id="message" rows="4" value={this.state.message} onChange={e => this.setState({message: e.target.value})} placeholder = "..."></textarea> </div> <ul className="actions"> <li> <input type="submit" value="Send Message" className="special"/> </li> </ul> </form> </article> </div> ) } sendEmail() { const serviceId='...' const templateId='...' const userId='...' emailjs.send(serviceId, templateId, this.state, userId) } } export default Main
内容的提问来源于stack exchange,提问作者dulongj

