React表单组件onClick重复触发问题排查与解决
React表单提交后函数意外重复触发的排查与解决
我最近碰到个挺头疼的React表单问题:用户点击提交按钮后,组件因为外部props更新正常重渲染,但明明没再点按钮,处理提交的save函数却反复触发。一开始以为是组件重渲染时onClick绑定出了问题,后来才发现根源不在React的渲染机制上,而是Firebase的认证监听搞的鬼!
先给大家看看最初的简化组件代码:
class Form extends Component{ constructor(props) { super(props); this.state = { input: '', } } save() { // do something // and something else... alert('data saved!'); } render() { return ( <div> <div> <input type="text" onChange={(e) => {this.setState({input: e.target.value})}} value={this.state.input} /> </div> <div onClick={this.save.bind(this)}> <span>submit</span> </div> </div> ) } }
问题根源排查
折腾了半天后发现,save函数里的Firebase认证状态监听才是罪魁祸首!原来每次调用save都会注册一个新的onAuthStateChanged监听器,而这个监听器会在认证状态发生变化时持续触发——哪怕组件更新和它无关,只要认证状态有变动(比如用户登录状态的隐性更新),这个监听器就会执行,导致alert('data saved')反复弹出,看起来像是onClick被重复触发了。
当时的save函数是这样的:
save () { firebase.auth().onAuthStateChanged(function(user) { if (user) { // do something // and something else alert('data saved'); } else { // do something else } }); }
解决办法
我的思路是:把监听器赋值给组件实例的变量,在监听器触发完成任务后,立即取消这个监听,避免后续不必要的执行。修改后的代码如下:
save () { const that = this; this.firebaseListener = firebase.auth().onAuthStateChanged(function(user) { if (user) { // do something // and something else alert('data saved'); that.firebaseListener = null; } else { // do something else } }); // 确保如果已有监听器先清理 this.firebaseListener && this.firebaseListener(); }
这个方案的核心是每个提交操作只绑定一次监听器,且完成后立即清理,这样就不会因为认证状态的后续变化反复触发save里的逻辑了。目前测试下来完全解决了问题,而且也不影响组件正常重渲染和用户重新提交表单的需求~
内容的提问来源于stack exchange,提问作者NatashaC
相关产品推荐
相关产品推荐

