【问题标题】:onClick called repeatedly (not supposed to) when component re-rendersonClick 在组件重新渲染时重复调用(不应该)
【发布时间】:2018-06-24 06:16:12
【问题描述】:

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

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

但是,当组件更新时,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 auth 事件侦听器,以确保用户经过身份验证。它看起来像这样:

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

到目前为止,这似乎工作......

【问题讨论】:

  • 你试过使用 preventDefault() 吗?
  • 您是在其他地方使用save 函数还是它只是附加到div 上的onClick
  • @margaretkru 它只附加到这个特定的onClick
  • 您的代码运行良好!我认为你在另一个函数/动作中调用 save 。检查这个:jsfiddle.net/69z2wepo/98160
  • 我看不出有任何理由在重新渲染后再次调用此函数。你能把代码贴在你使用表单组件的地方吗?

标签: javascript reactjs


【解决方案1】:

关于您的 Firebase 问题,请参阅以下答案:How to remove the new firebase onAuthStateChanged listener in react

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

不要在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>
    )
  }
}

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

【讨论】:

    猜你喜欢
    • 2018-08-12
    • 2019-06-01
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    • 2020-03-08
    • 1970-01-01
    • 2021-01-22
    • 2020-06-11
    相关资源
    最近更新 更多