Javascript 了解react功能组件中的点击事件和内存

Javascript 了解react功能组件中的点击事件和内存,javascript,reactjs,events,google-chrome-devtools,Javascript,Reactjs,Events,Google Chrome Devtools,我一直在使用函数组件和钩子,现在我正试图深入挖掘事件以及它们在内存中的存储方式。我一直在使用chrome开发工具性能选项卡来监视行为。有几件事我还不清楚,也许有人能帮我澄清一下 所以我做了3个不同的设置。第一个显示每个渲染多次添加事件的明显内存泄漏的事件。最终导致崩溃或渲染无限循环。或者至少这看起来是正在发生的事情 const App = () => { const [count, setCount] = React.useState(0); const onKeyDown = (

我一直在使用函数组件和钩子,现在我正试图深入挖掘事件以及它们在内存中的存储方式。我一直在使用chrome开发工具性能选项卡来监视行为。有几件事我还不清楚,也许有人能帮我澄清一下

所以我做了3个不同的设置。第一个显示每个渲染多次添加事件的明显内存泄漏的事件。最终导致崩溃或渲染无限循环。或者至少这看起来是正在发生的事情

const App = () => {
  const [count, setCount] = React.useState(0);
  const onKeyDown = () => setCount(count => count + 1);


  document.addEventListener('keydown', onKeyDown); 

    return (
    <div className='wrapper'>
      <div>Click any key to update counter</div>
      <div className='counter'>{count}</div>
    </div>
    );
};

ReactDOM.render(<App />, document.querySelector("#app"))
这表明每个侦听器的额外事件调用明显增加。请参阅事件日志,然后增加已添加事件的阶梯

下一步

结果更好,因为侦听器一次只调用一个调用。 但我注意到听众人数仍在增加。当他们被加入的时候,这个尖峰就没有那么尖锐了。但是听众的数量是以千计的。这些听众都在哪里被添加。它是JSFIDLE添加的侦听器。最好将此测试隔离在JSFIDLE之外的html页面中

然后,我阅读了关于使用hook useCallback的内容,它会记忆函数并返回函数的现金版本。所以我试过这个

const App = () => {
  const [count, setCount] = React.useState(0);

    const cb = React.useCallback(() => {
      console.log('cb');
      setCount(count => count + 1);
    }, [] );

    return (
    <div className='wrapper'>
      <div onClick={cb}>Click any key to update counter</div>
      <div className='counter'>{count}</div>
    </div>
    );
};

ReactDOM.render(<App />, document.querySelector("#app"))
但这与上次使用useEffect的测试结果类似。 听众数量仍然惊人,但不会像第一次测试那样崩溃。 那么,我错过了使用UseCallbackHook进行记忆的一些东西,这是怎么回事呢。侦听器看起来像是被疯狂添加的,而不是被垃圾收集的


我将在不使用jsfiddle的情况下隔离此测试,但我只是想先发布到社区以获得一些关于此的见解

在React中不使用addEventListener

相反,您可以这样做:

const App = () => {
  let count = 0;
  const onAddHandler = () => {    
    count++;
    console.log(count);
    this._count.innerText = count;   
 }
 return (
    <div className='wrapper'>
       <div onClick={()=>onAddHandler()}>Click any key to update counter</div>
       <div className='counter' ref={(el) => this._count = el}></div>
       </div>
  );
}
另外,不确定为什么要使用React.useState。功能组件的全部要点是它们是无状态的。我不喜欢在功能组件中使用这个新的useState钩子

您可能希望使用钩子的示例如下:

import React, { useState, useEffect } from 'react';
import {render} from 'react-dom';

function Example() {
   const [count, setCount] = useState(0);

   useEffect(() => {
     document.title = `You clicked ${count} times`;
   });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
   </div>
 );
}

render(<Example />, document.getElementById('root'));
React的文件说

如果您熟悉React类生命周期方法,您可以 将效果挂钩用作componentDidMount、componentDidUpdate和 组件将联合卸载


谢谢你,查尔斯。我使用addEventListener纯粹是以内存泄漏为例来说明它在devtools中是如何工作的。这个问题是关于开发工具以及如何阻止不必要的侦听器被添加到内存中。在函数组件中使用挂钩也是完全正常的,并且是React文档的一部分。您的hook示例是正确的,但它仍然没有告诉我为什么添加了大量侦听器。我想您还没有检查性能开发工具中的最后一个示例。另外,每次单击按钮时都要添加一个新的匿名函数onClick={=>}另一个注释中不清楚的注释。在React中不使用addEventListener!所以你说这是完全不正确的反应。文件。添加了“键控”列表,ON键控;您能告诉我们如何使用React添加文档侦听器吗?在React中,您只需创建一个事件处理程序,而幕后React可能会在幕后为您创建addEventListener。例如,在我的第一个示例中,我创建了一个arrow函数onAddHandler。React使用了一个称为虚拟DOM的概念,它是文档中DOM的副本。顺便说一下,我在开发工具中运行了我的示例,只看到了使用箭头函数技术的EventListener的一条简单路线。另外,您的回调可能在每次渲染、更新和装载事件中都会被调用,因此有很多事件侦听器是有意义的。对,但您指的是我所说的文档元素上的单击事件。addEventListener'keydown',onKeyDown;这是我知道如何向文档添加处理程序的唯一方法?你觉得还有别的反应方式吗?
import React, { useState, useEffect } from 'react';
import {render} from 'react-dom';

function Example() {
   const [count, setCount] = useState(0);

   useEffect(() => {
     document.title = `You clicked ${count} times`;
   });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
   </div>
 );
}

render(<Example />, document.getElementById('root'));