<p dir="auto">Describe what you were doing when the bug occurred:<br>
1.<br>
2.<br>
3.</p>
<hr>
<h2 dir="auto">Please do not remove the text below this line</h2>
<p dir="auto">DevTools version: 4.10.1-f160547f47</p>
<p dir="auto">Call stack: at updateTree (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:19702:53)<br>
at getCommitTree (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:19574:26)<br>
at ProfilingCache_ProfilingCache.getCommitTree (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:20115:11)<br>
at CommitFlamegraphAutoSizer (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:34161:33)<br>
at Hh (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:12807:7)<br>
at qi (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:13457:7)<br>
at mk (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:16074:86)<br>
at lk (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:15459:11)<br>
at kk (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:15451:23)<br>
at ck (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:15435:5)</p>
<p dir="auto">Component stack: at CommitFlamegraphAutoSizer (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:34144:50)<br>
at div<br>
at div<br>
at div<br>
at SettingsModalContextController (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:28206:3)<br>
at Profiler_Profiler (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:35772:50)<br>
at ErrorBoundary_ErrorBoundary (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:29219:5)<br>
at PortaledContent (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:29336:32)<br>
at div<br>
at div<br>
at ProfilerContextController (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:32934:3)<br>
at TreeContextController (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:24322:3)<br>
at SettingsContextController (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:24811:3)<br>
at ModalDialogContextController (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:29404:3)<br>
at DevTools_DevTools (chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/main.js:36207:3)</p>
<p dir="auto">React components could use some way to dynamically add a handler to be called on unmount. Either some event handler like way (<code class="notranslate">this.addUnmountHandler</code>) or some other way to register a 'destructor'/destroy method for an object that a component is holding on to.</p>
<p dir="auto"><code class="notranslate">componentWillUnmount</code> exists but it does not scale well.</p>
<ul dir="auto">
<li>Every time you hold on to something you have to maintain two sections of code, with the cleanup code being separate from the rest of the code.</li>
<li>If you try to cleanup your code using helpers adding the cleanup code could be done in the very same function. But <code class="notranslate">componentWillUnmount</code> doesn't allow that.</li>
<li>Sometimes you end up adding a <code class="notranslate">this._fooSomethingProp</code> to a component you wouldn't normally need, just so that you can hold on to the destructor for use in <code class="notranslate">componentWillUnmount</code> because you can't add the cleanup code in the same closure you set it up in.</li>
</ul>
<hr>
<p dir="auto">Here's one sample use case of mine for unmount handlers.</p>
<p dir="auto">React is discouraging the use of mixins so I've been trying to move towards alternative patterns in new code. Some helpers only make sense on a component itself and wont work as a special component or a higher-order component.</p>
<p dir="auto">For some of these needs I've come up with a pattern that involves passing the component to a helper function that will mutate the component and provide some sort of service which is linked to the component.</p>
<p dir="auto">Two examples from my codebase:</p>
<p dir="auto"><code class="notranslate">ctxApi</code> provides a component with a version of my internal api which is 'scoped' to the component so that if the component is unmounted all of the api requests' HTTP requests are aborted.</p>
<p dir="auto"><code class="notranslate">setPending</code> adds a key to a pending state set and returns a <code class="notranslate">pending.cleanup</code> that will unset it, which is intended to be passed to a <code class="notranslate">.finally</code> handler. This pattern provides my buttons, etc... with pending text and spinners while waiting for HTTP requests.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="resendConfirmation(email) {
    var pending = setPending(this, `${email}:resendConfirmation`);

    ctxApi(this)
        .then((api) =&gt; api.post('/self/resendConfirmationEmail', {email}))
        .then(() =&gt; alertifyjs.notify(&quot;Confirmation message sent&quot;))
        .fin(pending.cleanup)
        .catch(ignoreAbort)
        .catch(notifyOnError)
        .done();
}"><pre class="notranslate"><span class="pl-en">resendConfirmation</span><span class="pl-kos">(</span><span class="pl-s1">email</span><span class="pl-kos">)</span><span class="pl-kos"></span> <span class="pl-kos">{</span>
    <span class="pl-k">var</span> <span class="pl-s1">pending</span> <span class="pl-c1">=</span> <span class="pl-en">setPending</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">,</span> <span class="pl-s">`<span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">email</span><span class="pl-kos">}</span></span>:resendConfirmation`</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-en">ctxApi</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span>
        <span class="pl-kos">.</span><span class="pl-en">then</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">api</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s1">api</span><span class="pl-kos">.</span><span class="pl-en">post</span><span class="pl-kos">(</span><span class="pl-s">'/self/resendConfirmationEmail'</span><span class="pl-kos">,</span> <span class="pl-kos">{</span>email<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
        <span class="pl-kos">.</span><span class="pl-en">then</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s1">alertifyjs</span><span class="pl-kos">.</span><span class="pl-en">notify</span><span class="pl-kos">(</span><span class="pl-s">"Confirmation message sent"</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
        <span class="pl-kos">.</span><span class="pl-en">fin</span><span class="pl-kos">(</span><span class="pl-s1">pending</span><span class="pl-kos">.</span><span class="pl-c1">cleanup</span><span class="pl-kos">)</span>
        <span class="pl-kos">.</span><span class="pl-en">catch</span><span class="pl-kos">(</span><span class="pl-s1">ignoreAbort</span><span class="pl-kos">)</span>
        <span class="pl-kos">.</span><span class="pl-en">catch</span><span class="pl-kos">(</span><span class="pl-s1">notifyOnError</span><span class="pl-kos">)</span>
        <span class="pl-kos">.</span><span class="pl-en">done</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">The problem is that these helpers often need cleanup on unmount. <code class="notranslate">ctxApi</code> needs to abort requests on unmount. And <code class="notranslate">setPending</code> needs to break references so <code class="notranslate">setState</code> isn't called and it doesn't prevent gc. And while I can require that a call to a cleanup function be placed into <code class="notranslate">componentWillUnmount</code>. That is unnecessary boilerplate and easy to forget.</p>
<p dir="auto">It would be much preferable for these helpers to be able to register an unmount handler on the component instance so they can implicitly clean themselves up.</p>