We remove event listeners to prevent memory leaks, redundant executions, and performance degradation.
Key takeaways:
Event listeners in React enable dynamic responses to user interactions.
Improper handling of event listeners can cause memory leaks and performance issues.
Use
useEffect
with cleanup functions to manage event listeners in functional components.Empty dependency arrays in
useEffect
ensure effects run only once after the initial render.Use
useRef
for direct DOM manipulation and attaching custom event listeners.Always clean up event listeners during unmounting or re-renders to avoid resource wastage.
Proper event listener management ensures responsive, efficient, and bug-free applications.
In React development, managing event listeners effectively is a fundamental practice for building responsive and efficient applications. Event listeners allow your app to respond dynamically to user interactions, such as clicks, keypresses, or window resizing. However, improper handling of these listeners can lead to issues like memory leaks, performance degradation, or unexpected behavior.
This Answer will walk you through best practices for adding and cleaning up event listeners in React, ensuring your components remain optimized and bug-free. Whether you're using functional components with hooks or class components, mastering these techniques will elevate the reliability and maintainability of your React applications.
useEffect
hook for cleanupHere is the code for adding and removing event listeners:
ãF ) 95@@ °nPNG IHDR(-SäPLTE""""""""""""""""""2PX=r)7;*:>H¤-BGE8do5Xb6[eK®K¯1MU9gs3S\I§:gt'03@{V¹ÔT´ÏA}V»Ö@y6\fH¦-CII¨E+;@7_i7_jFJ«K°H£-BHaÚû,@FCL³&.0W½ÙN£ºI¨$)+BJªR¯È?v>s>uS±Ê=qP©ÁP¨ÀP§¿,?D4U^%+-M ¶K®%+,2OX+<AL²#&&D%,.I©vôTötRNSIæçJäeÀe¦©IDATxMµZEAÿÙ³ îî%R¡ïßáTThÇG »,Á®Å=²ÒîmífímnfA$â>!¦gºôHg½Eßܵ} Ý»ýº¼kdú§¯JoÎ3æL"J¹ ÌÕüQ$âçļffµ,é5i9̯H¨/mBwÍÜw;D Ø+&W«ª¹¨Dôo@Ê´RI©ÐB¡om.Û³ÀIEND®B`PNG IHDRשÍÊePLTE""""""""""""""""""""""""2RZN¢¹J«3R[J¬)59YÁÞ0KS4W`Q«ÄL²%+-0JR)6::gtC"##?vU·Ñ?w<n{&-/YÂß=q:iuBA}A{B/IPP§¿=qK®_ÔóL³$();lzR¯ÉaÚûI¨ZÆã3U^1MU3T]ZÅâI§X¿ÜF-BGP¨À6[e,@E5ZdO§¿-BHX¿Û+=AW¾Ú,@FW¼ØQªÃ?v W¼×+<A@y"#$\Ìê4Wa\ÌëS²Ì$(*.EL^ÑñVºÕ6]h#$%G¡#&';jwV¹Ô-CIL±ZÄá^Ðï>uS°Ê/HNM ·_Õõ\ËéM ¶8doD D>t+=B[Èæ,>C>t<o}@y0LS.EKT´Î$'(%,.A~W½ÙC%+,\ÊèC!ätRNSíîG¾ÖOIDATxlÃB¶Q u´ß_ȳ<˦Ýveê²óa6Aξûv¢{@ÎE'ÞdIÕ!çí ðCÔTþg1ÂE(ÏñSQsâi Ä Zÿ·V¹Ð)ég!ªhÎùtéº-i}µµ<Õ?¶lBZaÄ´4{DÓâ»_e8¥yÇÀ3)¥?°f;8.ã¤tÌ=å; :ã52fKZìlù¨ØÍ9.#ÒAÁqÌúÛ®£Vÿ`=$¬Â?_¶¾®ÔqMç.ïJ$ ?^q÷ñíÛï.},ìsæÝ_TttÔ¾1#/(ì-[è`è`ÌÚïÅðZd5?ÎebZ¿Þi.ÛæìqÎ+1°}Â5ùïçd¨GÏøIEND®B`PNG IHDR D¤ÆAPLTE"""""""""""""""""""""""""""2RZVºÖ_ÔôU·Ñ=r$()'25]ÎíC0LS<o}XÀÜX¿Û0JQ=p~D<n{VºÕE8do_ÔóEFH¥9dp_ÕõH¤I¨F6[e`Ö÷`×øL³/GM_ÓòU¸Ó'02P©Á/IPPªÂX¿Ü&/1;ly3R[`ØøG¡T³Í\ÌêaÚû1OW"##Q«ÄaÙúR®Ç=q`Öö.EL+=ATµÐ-CIK®#&'C^ÐïI¨&.04U^^Ñð@yZÇä$(*[Éç^Ññ,?DR¯É"#$1NV1MTD >u;kxG R¯È/HN&-/@y>s>t@z]ÍìP¨À$'(D]Ïî<n|0JRU·Ò×\¼ tRNS%ñ'ïó(ò~ÑÝèIDATxC1F_Ý¿MmÛ¶4¶m{ÿ¤nçáÓ ®A$à$b HeøTãWÄÂhh´:PtZ Q«0@.`Þ`4-V`³Zì&A#ÁébkÝÄãñúØ>.''ø`C$FØÏ (±x"6XácTÚéL§@Iù;dd-¹|¾P,È9¡RÕÍf3¢¿F½VmMíX§ÚíÍç@Y7ÎõºÕN¬=åÈʪu }Ö¬«+eaiq ¤Ö76íÝ=h ûZìíîlë}á¨Ê±¥[F«I9A¹k9¥Öëä3¢Ã9ΡóqB~Øáb¸ÃåU_¸^Ü[·ôwý{zvzÙ(£(£(þfòqÉGÉïkñÏçY¾ÿªfäòÇ~à:*4ÓQ\O> ¼<×úW£éÍZ|ÞÅ7ñïjTÔäãn½»¢®`$Hð+ò¿GOñûð*èxø¥X*|^ÿdIEND®B`PNG IHDR@@·ì:PLTE"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""%+-@yW¼×`×ø^ÑñS²ÌC,>C*8<XÁÝaÚûaÙùMµ+<AaÙúXÀÜ#%%TµÐL´=q>uK°`ÖöA}L±8do=r%+,@y^ÐïS²Ë)59=qP©ÁU·Ò"#$PªÂ\Êè0JQQªÃ"##U·Ñ#&&_Ôô>t>s`Øø_Ôó5Yc1OW5Zd1NV+=B1MU+;@/GM\Ìê*;?3S\)8<2RZ_Õõ+=A]Ïî,@F,@E&-/0KS7alO¦¾9dp8amB~EP¨ÀN¢¹'023T]]Îí?x3U^C6\gU¸Ó&.0D7_iRÆH¥I¨M ¶$(*?v ZÆãX¿Ü-AG#$%[Éç8co[ÈæW½ÙC'25?v8bn%*+L²N£º2PX)7;=p~(58^ÒòP§¿4WaQ«ÄT´Ï0JRQ¬ÅT´ÎI¨6]hR¯ÉT³Í0LSF9eqEE9gsFC#&'\Ëé`Ö÷&/16\fBA{R®Ç]Íì(47%,.*:>*9=9fr:gt7^iU¶Ð?wZÇäX¿Û^ÑðQÅH£)6:V¹Ô'034U^E.EL.FMK®@zS×tRNS*×øÖý »½+üùóÔ,ØúôÀ=VIDATx¤ËµC!ÐïC|ÿãÚ^yR]ÕMÛáO]ßÔÕÝ0NÈ2ÍËí¿"ªª¢(0Vã(ÀY%PDT-~(m¬ó!âKÞY£~´üIÒf{³ÛÞáa¼§§ô3ÕOp&Ф¡x÷#jôÚ¶mméòc)]m¤É)Ƨgfçhk²ñÎÒ ægg¦ÇìÐ+XÅêuiyVת·k«°²\[ü:,Ø6ØÜjIJ ;»"»;°×XùþÛfÁáÇÍûýSÎÎÏÏ8=Þo¾;æèÐ(öÓ¥BkÔeûÍ\7p+mîîáþNÚ<ÀQðOÒæùô³´yg»ttÐëoý½£ìVð»Òäsýü¬ø&_ðaüïV~à·Ö?*8àQ ;8¥Á,¸¤f¥1Üx¤×§ñ*øÑA¯Ôð°a#±³¶¦#nPi+¼¶CÈ,ÆèäÍ_áNbÑáøçHB*ÚÒ¦ L(^<ñÃL6pJ¾PÉ¥©¢%"R,ä9Èe3eRËa1( ¢ßqÇ8Ù´mK˱mƶmÛü·yi!èΪYÏuë ÀÏ_Àï?i÷ý+òÄA|ù{´?¿_En).JËD¤< ©¬¢Z\Ts©R*( ¯©J uX/ 4J9¡5·DEµ4kÇ4&i¥V4Ú¡®Ð¯vsf:àg,¢èBC»î$¶ºÍùîá@ôI_?<!^ÈàÓ½ÇöäõB%Làw±FD1Á¨(F±øH%0Ʊ¿ÅØ(¢0ÅÄ'ÅæN.0u@íYPWìIüaNâKÄ?ðÓµ=ev/c±Ó0c0÷2Êë:06R-uÒÄ\Q̶ää´¼µ6R# ÆF³6Òñ·rÕìuæmâðÂIñi~ Åü ÃsPþ"±ó¼ eiyå£ËPàãÊò§¡ÝÒ,S]U¦ºV ªÖ©®Z¦êoëë·xzãâÆSnm¬{ÚºwaÙÏ Å»´Ýõ(mg/®þå½À¿¼û[§b³µq¶Å&Õ¯¹$ñzÈH>aÌKT1/æø1O0¾.hÍYþAÓö£ -ê>Ûº«¢XÕ¢î}ߨëÛÑ;ÃöN´ØvÅýθÿ1ë×ÄO@&v/Äþ_ö\ôÇ\í.½+0;!fʦ´Ó% JY·OÂ'/Å]_;ßÀ'"&Nªn aQ^cx¦AáÒIEND®B`
Here's an explanation for the code given above:
Line 1: We import React, useState
, and useEffect
hooks from the react
package.
Line 3: We define a functional component called App
.
Line 4: We use the useState
hook to create a state variable called clickCount
initialized to 0
. setClickCount
is the function to update this state.
Lines 7–9: We define a function called handleClick
which updates the clickCount
state when called.
Line 12: We use the useEffect
hook to perform side effects in our component.
Line 14: Inside the useEffect
, we add an event listener for the 'click'
event on the document
element. When a click occurs, it will call the handleClick
function.
Lines 17–19: This is the cleanup function that useEffect
returns. It removes the 'click' event listener when the component is unmounted, preventing memory leaks.
Note: When you click the button, the
handleClick
function is invoked, and the component re-renders. During this re-render, the component is considered for unmounting, and the cleanup function specified in thereturn
statement ofuseEffect
is executed. This cleanup function removes the click event listener from thedocument
.
Line 20: We provide an empty dependency array ([]
) to useEffect
, which means it runs once. It ensures that the event listener is set up after the initial render.
Lines 22–27: We return JSX elements to render the component's user interface. It displays the current click count and a button that triggers the handleClick
function when clicked.
import React, { Component } from 'react';class App extends Component {handleResize = () => {console.log('Window resized');};componentDidMount() {// Add event listenerwindow.addEventListener('resize', this.handleResize);}componentWillUnmount() {// Remove event listenerwindow.removeEventListener('resize', this.handleResize);}render() {return <div>Resize the window and check the console!</div>;}}
Lines 4–6: Logs "Window resized" to the console whenever the handleResize
method is called.
Lines 8–11: The listener is tied to the handleResize
method, so the method will be called whenever the window is resized.
Lines 13–16: This ensures that handleResize
is no longer called after the component unmounts, preventing memory leaks or unexpected behavior.
Sometimes, the event listener logic depends on changing variables (e.g., props or state). In functional components, you can handle this by including those variables in the dependency array of useEffect
. The cleanup will occur whenever the effect re-runs due to a dependency change.
import React, { useEffect, useState } from 'react';function App() {const [count, setCount] = useState(0);useEffect(() => {const handleClick = () => {console.log(`Button clicked ${count} times`);};// Add event listenerdocument.addEventListener('click', handleClick);// Cleanup event listenerreturn () => {document.removeEventListener('click', handleClick);};}, [count]); // Effect re-runs when `count` changesreturn (<button onClick={() => setCount(count + 1)}>Click me</button>);}
Line 4: Tracks how many times the button has been clicked.
Lines 6–18: Runs the enclosed function after the component renders or updates. The second argument ([count]
) is the dependency array, which ensures the effect runs only when count
changes.
Lines 7–9: Logs the current count
value to the console whenever a click is detected.
Line 12: Adds a click
event listener to the document
and calls handleClick
whenever a click event occurs.
Lines 15–17: Removes the event listener whenever the component unmounts and the count
dependency changes, and the effect is re-run.
For custom or complex event handling, you might need direct DOM access via useRef
. This approach is useful for attaching event listeners to elements not managed by React.
import React, { useEffect, useRef } from 'react';function App() {const buttonRef = useRef(null);useEffect(() => {const handleClick = () => {console.log('Button clicked!');};// Add event listenerbuttonRef.current.addEventListener('click', handleClick);// Cleanupreturn () => {buttonRef.current.removeEventListener('click', handleClick);};}, []);return <button ref={buttonRef}>Click me</button>;}
Line 4: The ref
will point to the DOM element after it is rendered, enabling direct manipulation or event attachment.
Lines 6–9: The useEffect
hook executes the effect function after the component renders. The empty dependency array ([]
) ensures this effect runs only once (on mount).
Line 12: Attaches a click
event listener to the button element referenced by buttonRef
.
Lines 15–17: Removes the click
event listener during cleanup. This happens when the component unmounts or before the effect re-runs (if it had dependencies).
Proper management of event listeners in React is essential for optimal application performance and avoiding memory leaks. Using hooks like useEffect
to add and clean up event listeners ensures that side effects are handled safely and efficiently. By incorporating these best practices, developers can maintain the smooth operation of their applications while minimizing resource wastage.
Haven’t found what you were looking for? Contact Us
Free Resources