onClick 在组件重新渲染时重复调用(不应该调用)



我有一个反应组件,它是一个表单。当用户单击发送/提交按钮时,将调用一个函数来处理数据保存并执行其他一些任务。

问题是在用户单击按钮后,组件似乎重新渲染了几次(很可能是因为它从其他组件收到的外部道具被更新了)。这本身不是问题。

但是,当组件更新时,即使用户没有再次单击该按钮,也会再次调用onClick函数。

这是我不明白的部分。为什么组件更新时会触发onClick函数?我怎样才能防止这种情况发生?

我不想在用户单击按钮后停止组件更新。因为用户可能想要更改表单中的某些内容并再次发送。

简而言之,该组件如下所示:

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 () {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// do something
// and something else
alert('data saved');
} else {
// do something else
}
});
}

由于某种原因,该事件侦听器在用户提交后多次触发(它不应该触发)。底线是他与组件更新无关。

我现在为事件侦听器分配了一个值,并在触发一次后将其设置为 null,如下所示:

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();
}

到目前为止,这似乎正在起作用...

关于你的火力基地困境,请看这个答案: 如何在 react 中删除新的火碱 onAuthStateChanged 侦听器

听起来您走在正确的轨道上,但您可能希望在生命周期的早期设置身份验证侦听器。这样,您的用户在尝试保存表单之前就知道他们已经登录了。不过,这取决于您的用例。

不要在render中使用箭头函数或bind。请改为执行以下操作:

class Form extends Component{
constructor(props) {
super(props);
this.state = {
input: '',
}
this.handleChange = this.handleChange.bind(this);
this.save = this.save.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
save() {
// do something
// and something else...
alert('data saved!');
}
render() {
return (
<div>
<div>
<input
type="text"
onChange={this.handleChange}
value={this.state.input}
/>
</div>
<div onClick={this.save}>
<span>submit</span>
</div>
</div>
)
}
}

此更改应修复表单的重新呈现。这是因为每次调用渲染时函数都会更改,这可能会触发重新渲染。

最新更新