Languages
[Edit]
EN

Correct way to use addEventListener in React components

5 points
Created by:
Fletcher-Peralta
778

While writing source code in React, if we are beginners, we do not think about correct way of using addEventListener() functions - even, we do not think why we should use it.

 

You may ask: Why I should use addEventListener() if React provides API with events in props?

Let me explain: Some events that are not available by default in React props, like e.g. window key events.

In this article I am going to expalin what is the common mistakes and how to deal with them.

 

Code with bugs

I will explain the problem on component that listens for Ctrl+a keys pressed. The component that uses addEventListener() is unmounter and mounted after clicks to the button.

const MyComponent = () => {
  	useEffect(() => {
    	window.addEventListener('keyup', (e) => {
        	// source code here ...
        });
        // <-------- bug is here
    },[]);
	return (
      <div>{/* components here ... */}</div>
    );
};

Always when MyComponent is re-rendered keyup event listener is added to window object. After long time of the application working we have hundreds or even more listeners that calls callbacks.

That approach may lead to serious bugs, and performance issues after long application usage.

 

Fixed code

To solve the problem it is necessary just to call function that cleans up component. That function is the function returned from useEffect() function.

So:

useEffect(() => {
    const callback = (e) => {
    	setVisible(e.ctrlKey && e.key === 'a');
    };
	window.addEventListener('keyup', callback);
    return () => window.removeEventListener('keyup', callback);  // <-------- fix is here
},[]);

The correct source code should be:

const MyComponent = () => {
  	useEffect(() => {
        const callback = (e) => {
        	// source code here ...
        };
    	window.addEventListener('keyup', callback);
        return () => window.removeEventListener('keyup', callback); // <-------- fix is here
    },[]);
	return (
      <div>{/* components here ... */}</div>
    );
};

Hint: check this article to see runable example.

 

Reusable event hook

It is the best to use some hook that releases events for us by self.

The hook can may be created in the following way:

const useEvent = (object, event, callback) => {
    useEffect(() =>{
        object.addEventListener(event, callback);
        return () => object.removeEventListener(event, callback);
    }, []);
};

The correct source code with event hook will be:

const useEvent = (object, event, callback) => {
    useEffect(() =>{
        object.addEventListener(event, callback);
        return () => object.removeEventListener(event, callback);
    }, []);
};

const MyComponent = () => {
  	useEvent(window, 'keyup', (e) => {
        // source code here ...
    });
	return (
      <div>{/* components here ... */}</div>
    );
};

 

Conclusions

  1. React do not provide all pure JavaScript features.
  2. Whe we call that JS API we should take care of cleaning up after components were unmounted. The good exampel is addEventListener() function, what was described in the article.
  3. To simplyfy the problem with removing events in components we can use custom useEvent() hook.

 

See also

  1. React - useEffect cleanup on component unmount only

  2. JavaScript - detect Ctrl key pressed

  3. React - useEvent() hook

Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join