【问题标题】:React onClick function fires on renderReact onClick 函数在渲染时触发
【发布时间】:2021-06-05 11:45:29
【问题描述】:

我将 2 个值传递给子组件:

  1. 要显示的对象列表
  2. 删除函数。

我使用 .map() 函数来显示我的对象列表(如 react 教程页面中给出的示例),但该组件中的按钮在渲染时触发 onClick 函数(它不应该触发渲染时间)。我的代码如下所示:

module.exports = React.createClass({
    render: function(){
        var taskNodes = this.props.todoTasks.map(function(todo){
            return (
                <div>
                    {todo.task}
                    <button type="submit" onClick={this.props.removeTaskFunction(todo)}>Submit</button>
                </div>
            );
        }, this);
        return (
            <div className="todo-task-list">
                {taskNodes}
            </div>
        );
    }
});

我的问题是:为什么onClick 函数会在渲染时触发以及如何使其不触发?

【问题讨论】:

    标签: javascript reactjs button onclick dom-events


    【解决方案1】:

    甚至可以以比以下更易读的方式实现这一点:

    &lt;button onClick={() =&gt; somethingHere(param)}/&gt;

    const Comp = () => {
      const [triggered, setTriggered] = useState(false);
    
      const handleClick = (valueToSet) => () => {
        setTriggered(true);
      };
    
      return (
        <div>
          <button onClick={handleClick(true)}>Trigger</button>
          <div>{String(triggered)}</div>
        </div>
      );
    };
    

    &lt;button onClick={setTriggered(true)}/&gt;相比,它不会触发状态设置器并且不会导致太多的重新渲染 如果您没有任何参数可以传递给函数,那也没关系。

    【讨论】:

      【解决方案2】:

      问题在于你如何传递你的函数

      目前您没有传递函数而是调用它:

      <Button onClick={yourFunction()} />
      

      您可以通过两种方式解决此问题:

      <Button onClick={() => yourFunction(params)} />
      

      或者如果你没有任何参数:

      <Button onClick={yourFunction} />
      

      【讨论】:

      • 这对我有帮助,谢谢。
      • 救命稻草。尽管它在我的脑海里,但直到我看到它,我才想到它。谢谢
      【解决方案3】:

      您没有将函数作为参数传递,而是直接调用它,这就是它在渲染上启动的原因。

      如何解决

      有两种方式:

      第一

      <Button onClick={() => { 
      this.props.removeTaskFunction(todo);
      }
      }>click</Button>
      

      绑定就行了

      this.props.removeTaskFunction.bind(this,todo);
      

      【讨论】:

        【解决方案4】:

        这里有点晚,但这里是简单的答案。

        由于JS DOM渲染,直接方法会自行触发

        onClick={this.props.removeTaskFunction(todo)}
        

        匿名箭头函数方法。它会在点击时触发

        onClick={()=>this.props.removeTaskFunction(todo)}
        

        【讨论】:

          【解决方案5】:

          那是因为你是直接调用函数而不是将函数传递给onClick

          如果你传递了onClick={onClickHandler()},那么函数onClickHandler()也会在渲染期间执行,()指示函数一渲染就执行,这里不需要,相反,我们使用 onClick={onClickHandler} ,这将仅在指定事件发生时执行 onClickHandler。但是如果我们想将参数与函数一起传递,那么我们可以使用 ES6 箭头函数。 对于您的情况:

          <button type="submit" onClick={() => this.props.removeTaskFunction(todo)}>Submit</button>
          

          【讨论】:

            【解决方案6】:

            我有类似的问题,我的代码是:

            function RadioInput(props) {
                return (
                <div className="form-check form-check-inline">
                    <input className="form-check-input" type="radio" name="inlineRadioOptions" id={props.id} onClick={props.onClick} value={props.label}></input>
                    <label className="form-check-label" htmlFor={props.id}>{props.label}</label>
                </div>
                );
              }
            class ScheduleType extends React.Component
            {
                renderRadioInput(id,label)
                {
                    id = "inlineRadio"+id;
                    return(
                        <RadioInput
                            id = {id}
                            label = {label}
                            onClick = {this.props.onClick}
                        />
                    );
            
                }
            

            应该在哪里

            onClick = {() => this.props.onClick()}
            

            RenderRadioInput

            它为我解决了这个问题。

            【讨论】:

              【解决方案7】:

              JSX 将评估 JavaScript expressions in curly braces

              在这种情况下,this.props.removeTaskFunction(todo) 被调用并将返回值分配给onClick

              你必须为onClick 提供的是一个函数。为此,您可以将值包装在匿名函数中。

              export const samepleComponent = ({todoTasks, removeTaskFunction}) => {
                  const taskNodes = todoTasks.map(todo => (
                              <div>
                                  {todo.task}
                                  <button type="submit" onClick={() => removeTaskFunction(todo)}>Submit</button>
                              </div>
                          );
                  return (
                      <div className="todo-task-list">
                          {taskNodes}
                      </div>
                      );
                  }
              });
              

              【讨论】:

                【解决方案8】:

                JSX 与 ReactJS 一起使用,因为它与 HTML 非常相似,它给程序员一种使用 HTML 的感觉,而它最终会转译为 javascript 文件。

                编写一个for循环并将函数指定为 {this.props.removeTaskFunction(todo)} 将执行函数 每当触发循环时。

                要停止这种行为,我们需要将函数返回给 onClick。

                粗箭头函数有一个隐藏的 return 语句以及 bind 属性。因此,它将函数返回到 OnClick ,因为 Javascript 可以 也有返回函数 !!!!!

                使用-

                onClick={() => { this.props.removeTaskFunction(todo) }}
                

                这意味着-

                var onClick = function() {
                  return this.props.removeTaskFunction(todo);
                }.bind(this);
                

                【讨论】:

                  【解决方案9】:

                  对于那些不使用箭头函数但更简单的人......我在我的signOut函数后添加括号时遇到了这个......

                  替换这个&lt;a onClick={props.signOut()}&gt;Log Out&lt;/a&gt;

                  有了这个&lt;a onClick={props.signOut}&gt;Log Out&lt;/a&gt; ...! ?

                  【讨论】:

                  • 实际上这根本不适合我。我传递了函数并且从未添加括号,它仍然在渲染时触发。不确定自 19 年 2 月以来这是否发生了变化,但分配像 Long Nguyen 和 Vishal Bisht 的回答这样的功能解决了这个问题。
                  【解决方案10】:

                  因为您调用的是该函数而不是将函数传递给 onClick,所以将该行更改为:

                  <button type="submit" onClick={() => { this.props.removeTaskFunction(todo) }}>Submit</button>
                  

                  =&gt; 称为箭头函数,在 ES6 中引入,将在 React 0.13.3 或更高版本上得到支持。

                  【讨论】:

                  • 您也可以避免使用这些箭头函数花括号。我认为符合最佳实践:onClick={() =&gt; this.props.removeTaskFn(todo)}
                  • 您能再解释一下吗?我知道人们一直说这不是最佳实践,但我想用 () => 了解这里发生的事情,我了解箭头函数是什么,但不知道这是什么 () 以及为什么这不好?
                  • @wuno () 是你的匿名函数的参数。这里是空的,因为我们没有传入任何参数。想象一下()是function()的()。现在关于为什么在 render() 函数中绑定不是最佳实践是因为在每次渲染时,我们都将函数重新绑定到组件,这可能非常昂贵。
                  • @LongNguyen 这就是我要找的!非常感谢
                  • 非常感谢,这个问题太明显了,我没注意到,很好的答案!
                  【解决方案11】:

                  onClick 属性的值应该是函数,而不是函数调用。

                  <button type="submit" onClick={function(){removeTaskFunction(todo)}}>Submit</button>
                  

                  【讨论】:

                  • 不要在渲染内部的事件调用中使用匿名函数——它会触发另一个渲染
                  【解决方案12】:

                  不调用函数,而是将值绑定到函数:

                  this.props.removeTaskFunction.bind(this, todo)
                  

                  MDN 参考:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

                  【讨论】:

                  • 恕我直言和许多其他人。您应该更喜欢无状态函数而不是类或绑定,因为它们会导致您产生不希望的副作用。因此,即使两个答案都正确,我相信一个比另一个更合适。
                  • 不推荐在渲染或组件中的任何其他地方直接绑定。绑定应该总是发生在构造函数中