简体   繁体   English

了解反应功能组件中的点击事件和内存

[英]Understanding click events and memory in react function components

I've been working with function components and hooks and i'm now trying to dig deeper into events and how they hold in memory.我一直在使用函数组件和钩子,现在我正在尝试更深入地研究事件以及它们如何保存在内存中。 I've been using chrome dev tools performance tab to monitor the behavior.我一直在使用 chrome 开发工具性能选项卡来监控行为。 There is a few things I'm not clear on and maybe someone can clear this up for me.有几件事我不清楚,也许有人可以为我澄清。

So I did 3 different setups.所以我做了3个不同的设置。 First one to show obvious memory leak of events been added multiple times per render.第一个显示事件明显内存泄漏的事件在每次渲染时添加了多次。 which eventually causes a crash or infinite loop of renders.这最终会导致渲染崩溃或无限循环。 Or at least thats what looks like is happing.或者至少那是看起来正在发生的事情。

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"))

This shows an obvious spike in extra event calls per listener.这表明每个侦听器的额外事件调用明显增加。 See event log and then increase ladder of events been added.查看事件日志,然后增加已添加的事件阶梯。

在此处输入图片说明

Next up接下来

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


 React.useEffect(() => {
   document.addEventListener('keydown', onKeyDown);
   return () => document.removeEventListener('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"))

The result was better in that the listener was only one call at a time.结果更好,因为听众一次只有一个电话。 But I noticed the listener count was still going through the roof.但我注意到听众人数仍在飙升。 The spike in when they got added wasn't as sharp.添加它们时的峰值并不那么尖锐。 but the count of listeners was in the thousand.但是听众的人数是千人。 Where are all these listeners getting added.所有这些听众在哪里被添加。 Is it listeners been added by jsfiddle. jsfiddle 是否添加了侦听器。 Probably best to isolate this test in just a html page outside jsfiddle.最好将这个测试隔离在 jsfiddle 之外的一个 html 页面中。

在此处输入图片说明

Then I read about using the hook useCallback which memoizes the function and returns the cashed version of the function.然后我读到了使用钩子 useCallback 来记住函数并返回函数的兑现版本。 So I tried this.所以我尝试了这个。

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"))

But this turned out to be similar to the last test using useEffect.但结果证明这与上次使用 useEffect 的测试类似。 Crazy amount of listeners still but no crashing like the first test.仍然有大量的听众,但没有像第一次测试那样崩溃。
So whats' the deal here am I missing something about memoizing using useCallback hook.那么这里的交易是什么我错过了使用 useCallback 钩子进行记忆的一些东西。 Listeners look like they are been added like crazy and not been garbage collected.侦听器看起来像是被疯狂添加而没有被垃圾收集。

I'm going to isolate this test without jsfiddle but just wanted to post to the community to get some insight on this first.我将在没有 jsfiddle 的情况下隔离此测试,但只是想发布到社区以首先对此有所了解。

You don't use addEventListener in React!你不要在 React 中使用 addEventListener !

Instead you'd do something like this:相反,你会做这样的事情:

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

Also, not sure why you're using React.useState.另外,不确定您为什么使用 React.useState。 The whole point of functional components is that they're stateless.功能组件的全部意义在于它们是无状态的。 I'm not fond of this new useState hook to be used in a functional component.我不喜欢在功能组件中使用这个新的 useState 钩子。

The example you were probably looking for using hooks is:您可能正在寻找使用钩子的示例是:

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'));

The React documentation https://reactjs.org/docs/hooks-effect.html says that React 文档https://reactjs.org/docs/hooks-effect.html

If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.如果您熟悉 React 类的生命周期方法,您可以将 useEffect Hook 视为 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM