title: What's useEffect execution order and its internal clean-up logic in react hooks?
body: <p>According to react document, <code>useEffect</code> will trigger clean-up logic before it re-runs <code>useEffect</code> part.</p>
  <blockquote>
  <p>If your effect returns a function, React will run it when it is time to clean up...</p>
  <p>There is no special code for handling updates because <code>useEffect</code> handles them by default. It cleans up the previous effects before applying the next effects...</p>
  </blockquote>
  <p>However, when I use <code>requestAnimationFrame</code> and <code>cancelAnimationFrame</code> inside <code>useEffect</code>, I found the cancelAnimationFrame may not stop the animation normally. Sometimes, I found the old animation still exists, while the next effect brings another animation, which causes my web app performance issues (especially when I need to render heavy DOM elements).</p>
  <p>I don't know whether react hook will do some extra things before it executes the clean-up code, which make my cancel-animation part not work well, will <code>useEffect</code> hook do something like closure to lock the state variable?</p>
  <p>What's useEffect's execution order and its internal clean-up logic? Is there something wrong the code I write below, which makes cancelAnimationFrame can't work perfectly?</p>
  <p>Thanks.</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="true">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>//import React, { useState, useEffect } from "react";
  
  const {useState, useEffect} = React;
  
  //import ReactDOM from "react-dom";
  
  function App() {
    const [startSeconds, setStartSeconds] = useState(Math.random());
    const [progress, setProgress] = useState(0);
  
    useEffect(() =&gt; {
      const interval = setInterval(() =&gt; {
        setStartSeconds(Math.random());
      }, 1000);
  
      return () =&gt; clearInterval(interval);
    }, []);
  
    useEffect(
      () =&gt; {
        let raf = null;
  
        const onFrame = () =&gt; {
          const currentProgress = startSeconds / 120.0;
          setProgress(Math.random());
          // console.log(currentProgress);
          loopRaf();
          if (currentProgress &gt; 100) {
            stopRaf();
          }
        };
  
        const loopRaf = () =&gt; {
          raf = window.requestAnimationFrame(onFrame);
          // console.log('Assigned Raf ID: ', raf);
        };
  
        const stopRaf = () =&gt; {
          console.log("stopped", raf);
          window.cancelAnimationFrame(raf);
        };
  
        loopRaf();
  
        return () =&gt; {
          console.log("Cleaned Raf ID: ", raf);
          // console.log('init', raf);
          // setTimeout(() =&gt; console.log("500ms later", raf), 500);
          // setTimeout(()=&gt; console.log('5s later', raf), 5000);
          stopRaf();
        };
      },
      [startSeconds]
    );
  
    let t = [];
    for (let i = 0; i &lt; 1000; i++) {
      t.push(i);
    }
  
    return (
      &lt;div className="App"&gt;
        &lt;h1&gt;Hello CodeSandbox&lt;/h1&gt;
        &lt;text&gt;{progress}&lt;/text&gt;
        {t.map(e =&gt; (
          &lt;span&gt;{progress}&lt;/span&gt;
        ))}
      &lt;/div&gt;
    );
  }
  
  ReactDOM.render(&lt;App /&gt;,
  document.querySelector("#root"));</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.production.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js"&gt;&lt;/script&gt;
  &lt;div id="root"&gt;&lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>