<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonathan Experton</title>
    <description>The latest articles on DEV Community by Jonathan Experton (@jxprtn).</description>
    <link>https://dev.to/jxprtn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F41091%2F224900dc-c832-42bb-9a1b-6f3b2c94ca56.png</url>
      <title>DEV Community: Jonathan Experton</title>
      <link>https://dev.to/jxprtn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jxprtn"/>
    <language>en</language>
    <item>
      <title>How to fix the React memory leak warning</title>
      <dc:creator>Jonathan Experton</dc:creator>
      <pubDate>Wed, 14 Apr 2021 12:52:48 +0000</pubDate>
      <link>https://dev.to/jxprtn/how-to-fix-the-react-memory-leak-warning-d4i</link>
      <guid>https://dev.to/jxprtn/how-to-fix-the-react-memory-leak-warning-d4i</guid>
      <description>&lt;p&gt;If you've ever worked with React function components and the &lt;a href="https://reactjs.org/docs/hooks-effect.html" rel="noopener noreferrer"&gt;useEffect&lt;/a&gt; hook, it's almost impossible that you've never faced this warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Warning: Can't perform a React state update on an unmounted
component. This is a no-op, but it indicates a memory leak in
your application. To fix, cancel all subscriptions and
asynchronous tasks in a useEffect cleanup function.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the warning I'm referring to as &lt;em&gt;the&lt;/em&gt; React memory leak warning because it is very easy to trigger and hard to get rid of if you don't understand what's happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the warning
&lt;/h2&gt;

&lt;p&gt;There are 4 important concepts here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Can't perform a React state update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;on an unmounted component.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;To fix, cancel all subscriptions and asynchronous tasks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;in a useEffect cleanup function.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won't explain what a memory leak is, instead I'll encourage you to read what is my go-to article about &lt;a href="https://blog.sessionstack.com/how-javascript-works-memory-management-how-to-handle-4-common-memory-leaks-3f28b94cfbec" rel="noopener noreferrer"&gt;memory management in Javascript&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a &lt;em&gt;state update&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;Given the following state initialization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A state update would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is &lt;em&gt;an unmounted component&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;A component is &lt;a href="https://reactjs.org/docs/react-component.html#unmounting" rel="noopener noreferrer"&gt;unmounted&lt;/a&gt; when it is removed from the DOM. It is the final step of a React component's life cycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are &lt;em&gt;subscriptions&lt;/em&gt; and &lt;em&gt;asynchronous tasks&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;Asynchronous tasks are callbacks sent to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#queue" rel="noopener noreferrer"&gt;&lt;em&gt;queue of callbacks&lt;/em&gt;&lt;/a&gt; of the &lt;a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ" rel="noopener noreferrer"&gt;event loop&lt;/a&gt;. They are asynchronous because they won't be executed until some conditions are met.&lt;/p&gt;

&lt;p&gt;Any mechanism that can add a callback to the &lt;em&gt;queue of callbacks&lt;/em&gt;, thereby deferring its execution until the fulfillment of a condition, can be considered as a &lt;em&gt;subscription&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;Promises&lt;/a&gt; when fulfilled or rejected&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout" rel="noopener noreferrer"&gt;&lt;code&gt;setTimeout&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval" rel="noopener noreferrer"&gt;&lt;code&gt;setInterval&lt;/code&gt;&lt;/a&gt; when a certain time has elapsed &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;Events&lt;/a&gt; when the event occurs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've skipped &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate" rel="noopener noreferrer"&gt;&lt;code&gt;setImmediate&lt;/code&gt;&lt;/a&gt; since it's not a web standard, and I'm simplifying things by referring to a unique &lt;em&gt;queue of callbacks&lt;/em&gt; when there's in fact multiple queues with  different levels of priority.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 1 - Asynchronous task in a Promise handler
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;someAsyncFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Here is the asynchronous task.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;someAsyncFunction()&lt;/code&gt; returns a &lt;code&gt;Promise&lt;/code&gt; we can &lt;em&gt;subscribe&lt;/em&gt; to by calling the &lt;code&gt;then()&lt;/code&gt; method with a callback function as the &lt;em&gt;task&lt;/em&gt; to execute when &lt;code&gt;someAsyncFunction()&lt;/code&gt; resolves. &lt;/p&gt;

&lt;h4&gt;
  
  
  Case 2 - Asynchronous task in a &lt;code&gt;setTimeout&lt;/code&gt; handler
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Here is the asynchronous task.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;setTimeout&lt;/code&gt; is usually called with a delay as a second argument, but &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#zero_delays" rel="noopener noreferrer"&gt;when left empty&lt;/a&gt;, the event handler will be executed as soon as the event loop starts to process the &lt;em&gt;queue of callbacks&lt;/em&gt;, but it is still asynchronous and has a significant chance to be executed after the component has been unmounted.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 3 - Asynchronous task in an event handler
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Here is the asynchronous task.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subscribing to an event is done by adding an event listener and passing a callback function to the listener. &lt;/p&gt;

&lt;p&gt;Until the event listener is removed or the event emitter is destroyed, the callback function will be added to the &lt;em&gt;queue of callbacks&lt;/em&gt; on every event occurrence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous tasks are side effects
&lt;/h3&gt;

&lt;p&gt;In React functional components any side effects such as data fetching or event handling &lt;a href="https://reactjs.org/docs/hooks-overview.html#effect-hook" rel="noopener noreferrer"&gt;should be done inside a useEffect&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;someAsyncFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Here is an asynchronous task.&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// There is another asynchronous task.&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is a &lt;em&gt;useEffect cleanup function&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup" rel="noopener noreferrer"&gt;Every effect may return a function that cleans up after it&lt;/a&gt;. This function is called when the component is unmounted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This is the cleanup function&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is wrong?
&lt;/h2&gt;

&lt;p&gt;React is telling us to stop trying to update the state of a component that has been deleted.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 1 - Asynchronous task in a Promise handler
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;someAsyncFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we've subscribed to a Promise, there's a pending callback, waiting for the Promise to settle, regardless of whether it has been fulfilled or rejected. &lt;/p&gt;

&lt;p&gt;If the React component is unmounted before the Promise completion, the pending callback stays in the &lt;em&gt;callback queue&lt;/em&gt; anyway.&lt;/p&gt;

&lt;p&gt;And once the Promise has settled, it will try to update the state of a component that doesn't exist anymore.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 2 - Asynchronous task in a &lt;code&gt;setTimeout&lt;/code&gt; handler
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is close to the previous case except that the condition for the callback to be executed is to wait 5000ms.&lt;/p&gt;

&lt;p&gt;If the React component is unmounted before this amount of time, it will also try to update the state of a component that doesn't exist anymore.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 3 - Asynchronous task in an event handler
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setDimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attaching handlers to events is different from the previous cases because events can occur multiple times and therefore can trigger the same callback multiple times.&lt;/p&gt;

&lt;p&gt;If the event emitter we've bound an event handler is not destroyed when the React component is unmounted, it still exists and will be executed on every event occurrence.&lt;/p&gt;

&lt;p&gt;In the above example, the event handler is bound to a global variable &lt;code&gt;Dimensions&lt;/code&gt;, the event emitter, which exists outside of the scope of the component. &lt;/p&gt;

&lt;p&gt;Therefore, the event handler is not unbound or garbage collected when the component is unmounted, and the event emitter might trigger the callback in the future even though the component doesn't exist anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing the problem
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Case 1 - Asynchronous task in a Promise handler
&lt;/h4&gt;

&lt;p&gt;Since it is not possible to cancel a Promise the solution is to prevent the &lt;code&gt;setIsVisible&lt;/code&gt; function to be called if the component has been unmounted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;someAsyncFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By leveraging &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#lexical_scoping" rel="noopener noreferrer"&gt;lexical scoping&lt;/a&gt;, we can share a variable between the callback function and the cleanup function.&lt;/p&gt;

&lt;p&gt;We use the cleanup function to modify the &lt;code&gt;cancel&lt;/code&gt; variable and trigger an &lt;a href="https://dev.to/jpswade/return-early-12o5"&gt;early return&lt;/a&gt; in the callback function to prevent the state update.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 2 - Asynchronous task in a &lt;code&gt;setTimeout&lt;/code&gt; handler
&lt;/h4&gt;

&lt;p&gt;To remove a callback bound to a timer, remove the timer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Case 3 - Asynchronous task in an event handler
&lt;/h4&gt;

&lt;p&gt;To cancel a subscription to an event, remove the event handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setDimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Dimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Global variables are never garbage collected so don't forget to remove event handlers manually if the event emitter is stored in a global variable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove any event handlers bound to event emitters that might not be removed when a component is unmounted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Promises cannot be cancelled but you can use lexical scoping to change the behavior of the callback from the &lt;code&gt;useEffect&lt;/code&gt; cleanup function by triggering an early return or &lt;a href="https://dev.to/witaylor/short-circuit-conditionals-in-javascript-54i2"&gt;short-circuiting&lt;/a&gt; the state update.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try to avoid timers, if you can't, be sure to always cancel them with &lt;code&gt;clearTimeout&lt;/code&gt; or &lt;code&gt;clearInterval&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;small&gt;Photo by &lt;a href="https://unsplash.com/@healing_photographer" rel="noopener noreferrer"&gt;Aarón Blanco Tejedor&lt;/a&gt; on &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;br&gt;
  &lt;/small&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Ref forwarding with React function components and Typescript</title>
      <dc:creator>Jonathan Experton</dc:creator>
      <pubDate>Mon, 29 Mar 2021 15:07:15 +0000</pubDate>
      <link>https://dev.to/jxprtn/ref-forwarding-with-react-function-components-and-typescript-20ip</link>
      <guid>https://dev.to/jxprtn/ref-forwarding-with-react-function-components-and-typescript-20ip</guid>
      <description>&lt;p&gt;While ref forwarding is well explained in the official documentation, it can be confusing to type it correctly with function components.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Typing the reference to be forwarded
&lt;/h3&gt;

&lt;p&gt;The reference is created with the &lt;a href="https://reactjs.org/docs/refs-and-the-dom.html#creating-refs" rel="noopener noreferrer"&gt;&lt;code&gt;createRef&lt;/code&gt;&lt;/a&gt; function. &lt;/p&gt;

&lt;p&gt;Unlike the &lt;a href="https://reactjs.org/docs/hooks-reference.html#useref" rel="noopener noreferrer"&gt;&lt;code&gt;useRef&lt;/code&gt;&lt;/a&gt; hook, which creates a &lt;code&gt;MutableRefObject&lt;/code&gt; whose &lt;code&gt;.current&lt;/code&gt; property might be initialized with an &lt;code&gt;undefined&lt;/code&gt; value, &lt;a href="https://reactjs.org/docs/refs-and-the-dom.html#creating-refs" rel="noopener noreferrer"&gt;&lt;code&gt;createRef&lt;/code&gt;&lt;/a&gt; returns an &lt;a href="https://github.com/facebook/react/blob/master/packages/react/src/ReactCreateRef.js#L17" rel="noopener noreferrer"&gt;immutable&lt;/a&gt; &lt;code&gt;RefObject&lt;/code&gt; so you don't need to bother with the initial value type being different than the final value type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// In real life, you don't need to explicitly type refTitle &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this example the reference will point to a &lt;code&gt;Text&lt;/code&gt; component therefore the &lt;code&gt;Text&lt;/code&gt; component is passed to &lt;a href="https://reactjs.org/docs/refs-and-the-dom.html#creating-refs" rel="noopener noreferrer"&gt;&lt;code&gt;createRef&lt;/code&gt;&lt;/a&gt; as a &lt;a href="https://www.typescriptlang.org/docs/handbook/2/generics.html#working-with-generic-type-variables" rel="noopener noreferrer"&gt;type argument&lt;/a&gt; to explicitly &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v16/index.d.ts#L792" rel="noopener noreferrer"&gt;type&lt;/a&gt; the referenced value.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Forwarding the reference to the child component
&lt;/h3&gt;

&lt;p&gt;With the &lt;a href="https://reactjs.org/docs/refs-and-the-dom.html#refs-and-function-components" rel="noopener noreferrer"&gt;ref attribute&lt;/a&gt; of the child component:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ParentComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChildComponent&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refTitle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hello, World!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Assigning the forwarded ref inside the child component
&lt;/h3&gt;

&lt;p&gt;As said in the documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By default, &lt;em&gt;you may not use the ref attribute on function components&lt;/em&gt; because they don’t have instances.&lt;/p&gt;

&lt;p&gt;If you want to allow people to take a &lt;code&gt;ref&lt;/code&gt; to your function component, you can use &lt;a href="https://reactjs.org/docs/forwarding-refs.html" rel="noopener noreferrer"&gt;&lt;code&gt;forwardRef&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then with the &lt;a href="https://reactjs.org/docs/forwarding-refs.html" rel="noopener noreferrer"&gt;&lt;code&gt;forwardRef&lt;/code&gt;&lt;/a&gt; function:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ChildComponentProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ChildComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forwardRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ChildComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ChildComponentProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ForwardedRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Name the component for debugging purpose and prevent eslint warning.&lt;/span&gt;
&lt;span class="nx"&gt;ChildComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ChildComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now there's an immutable &lt;a href="https://reactjs.org/docs/refs-and-the-dom.html#creating-refs" rel="noopener noreferrer"&gt;&lt;code&gt;RefObject&lt;/code&gt;&lt;/a&gt; available in the &lt;code&gt;ParentComponent&lt;/code&gt; that points to the &lt;code&gt;Text&lt;/code&gt; component inside the &lt;code&gt;ChildComponent&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Concrete example
&lt;/h3&gt;

&lt;p&gt;Here is an example with React Native where you can use ref forwarding to focus the device's screen reader on a text once the whole parent component is ready:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@jcgellidon" rel="noopener noreferrer"&gt;JC Gellidon&lt;/a&gt; on &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
