警告:由于<input type ="checkbox"/>发生的性能原因,会重复使用此合成事件

Ray*_*mi 16 javascript frontend reactjs react-redux

我一直在为一个类开发一个简单的react-redux todo示例,每次我检查并取消选中复选框输入时,我都会在控制台中看到几条警告消息.

您可以在以下图像中看到警告.

警告错误图像

我也在谷歌搜索警告信息,但找不到任何有效的解决方案.另外,我的注意力是看起来它试图访问本机事件和DOM元素的每个属性.

这是具有输入复选框的表示组件的代码

class TodoItem extends React.Component {
  state = {
    isChecked: false
  };
  handleCheckbox = () => {
    this.setState({
      isChecked: !this.state.isChecked
    });
  };
  render() {
    const { todos, onItemClick } = this.props;
    const { isChecked } = this.state;
    return (
      <div>
        <ul>
          {todos.map((todo, id) => {
            return (
              <li key={id} onClick={onItemClick}>
                <input
                  onChange={this.handleCheckbox}
                  type="checkbox"
                  checked={isChecked}
                />
                <label>
                  <span />
                  {todo.textInput}
                </label>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default TodoItem;
Run Code Online (Sandbox Code Playgroud)

我也在CodeSandbox上传了这个例子:https://codesandbox.io/s/k0mlxk1yqv

如果要复制此错误,则需要将项目添加到待办事项列表,然后单击复选框以选中并取消选中几次.

如果有人知道为什么这个警告标志不断出现以及如何禁用它们,我将非常感谢你的输入:)

Ada*_*lov 20

我建议尝试两种解决方案:

第一次改变

onChange={this.handleCheckbox}
Run Code Online (Sandbox Code Playgroud)

onChange={() => this.handleCheckbox}
Run Code Online (Sandbox Code Playgroud)

如果那行不通,请在“ handleCheckbox”中添加event.persist();如下代码:

handleCheckbox = (event) => {
  event.persist();
  this.setState({
    isChecked: !this.state.isChecked
  });
};
Run Code Online (Sandbox Code Playgroud)

  • React 文档对此是这样描述的:“SyntheticEvent 是池化的。这意味着 SyntheticEvent 对象将被重用,并且在调用事件回调后所有属性将被取消。这是出于性能原因。因此,您无法访问以异步方式发生事件。” 我不太明白,但我认为 React 在第一次使用后会丢失所有事件的属性。因此,当您传递没有 () =&gt; {return} 的方法时,它会在安装组件时调用传递的方法,然后丢失事件的属性。如果有人能证实这一点,我将不胜感激。 (2认同)
  • @WesselvanderLinden我认为,当使用array.map()函数时,如果没有唯一键的项会创建许多相同的项,React无法辨认哪个孩子触发了该事件,因此可能会导致崩溃。因此,使用ES6箭头功能将自动将“ this”绑定到唯一的一项。 (2认同)

w35*_*l3y 17

发生这种情况是因为event隐式传递给的onItemClick是在异步上下文中使用的。
正如Andre Lemay所说,您应该将需求分配给局部变量并对其进行引用。

就我而言,我有以下代码:

handleInput = e => { // <-- e = synthetic event
  this.setState(state => ({ // <-- asynchronous call
    data: {
      ...state.data,
      [e.target.name]: e.target.value // <-- this was causing the warnings (e.target is in an asynchronous context)
    }
  }));
};
Run Code Online (Sandbox Code Playgroud)

然后我将其更改为:

handleInput = e => {
  const { name, value } = e.target; // <-- moved outside asynchronous context

  this.setState(state => ({
    data: {
      ...state.data,
      [name]: value
    }
  }));
};
Run Code Online (Sandbox Code Playgroud)

  • 我确信有记录表明 `setState` 是异步的,但在这种情况下指出它对我非常有帮助。 (4认同)

小智 6

这可能有点晚了,但是我遇到了同样的问题,并且以我认为比亚当·奥尔洛夫的答案更好的方式解决了。我不认为这两个答案都直接适用于所问的问题,但是在搜索有关合成事件和复选框时会出现此问题,因此它和其他任何地方一样好...

我相信亚当是正确的,因为他相信React会清除SyntheticEvent对象的所有属性(这很有意义,因为React告诉我们它正在重用该对象)。

但是,除非您需要整个对象,否则我认为调用event.persist()并不是最好的解决方案,因为根据文档,它将从池中删除该对象(大概是有充分的理由将其放在那里) 。

如果要以异步方式访问事件属性,则应在事件上调用event.persist(),这将从池中删除综合事件,并允许用户代码保留对该事件的引用。

除了这样做,如果您只需要事件对象中的一个或两个值,则可以将它们分配给局部变量,然后在自己的函数内引用局部变量,如下所示:

<input type="checkbox" onChange={(event) => {
    let checked = event.currentTarget.checked; //store whatever values we need from from the event here
    this._someOtherFunction(checked)
} />
Run Code Online (Sandbox Code Playgroud)

这样,您不必以任何方式重组代码来避免执行任何依赖事件数据的异步操作,并且您也不必担心潜在的性能影响,因为您可以让React随心所欲地进行操作。事件池。


Eri*_*rix 5

类似的问题虽然我的设置是功能组件,材质 UI<Textform />输入。

上面提到的那个人event.persist();,谢谢你为我工作,但第一个建议没有明显影响,不确定那是不是因为我使用的是功能组件而不是类组件。(我不再使用类组件,只使用钩子功能)

还要注意建议使用 event.persist() 的警告信息。我的问题是我正在使用 onChange 捕获表单输入并将输入存储到我的状态中,在大约第二个或第三个字符之后它会抛出错误并使我的应用程序崩溃。

前:

    const handleChange = (e) => {
    
    setState((form) => ({
      ...form,
      [e.target.name]: e.target.value,
    }));
  };
Run Code Online (Sandbox Code Playgroud)

后:

    const handleChange = (e) => {
    e.persist();
    setState((form) => ({
      ...form,
      [e.target.name]: e.target.value,
    }));
  };
Run Code Online (Sandbox Code Playgroud)

因此,这似乎是类似问题的正确解决方案,虽然我没有使用复选框,但我使用的是表单输入, Material-UI <TextField />。我可以删除单行

e.persist();
Run Code Online (Sandbox Code Playgroud)

并且代码将再次失败,将其添加回来,一切都很好,没有崩溃没有警告。