title: React Hooks, setTimeout in useEffect not triggering until end, because of state updates
body: <p><strong>Context</strong>:</p>
  <ul>
  <li>New messages are added (e.g. every two seconds, using setInterval).</li>
  <li>Messages have status, either old or new. Newly added messages have a 'new' flag.</li>
  <li>After every 5 seconds, all 'new' messages are designated 'old'. (setTimeout)</li>
  </ul>
  <p><strong>Problem</strong>:</p>
  <ul>
  <li>Timeout is not triggering until the end. New messages are added, but they remain 'new' until all messages are added.</li>
  <li>I suspect that after every update the timeout is being reset/cleared and because the updates are occurring faster than the timeout, then the timeout callback never triggers in time (as a result only the final timeout get's triggered).</li>
  </ul>
  <pre><code>
  function useInterval(callback, delay) {
    const savedCallback = React.useRef();
    // Remember the latest callback.
    React.useEffect(() =&gt; {
      savedCallback.current = callback;
    }, [callback]);
    // Set up the interval.
    React.useEffect(() =&gt; {
      function tick() {
        savedCallback.current();
      }
      if (delay !== null) {
        let id = setInterval(tick, delay);
        return () =&gt; clearInterval(id);
      }
    }, [delay]);
  }
  
  const defaultMessages = [
    {
      message: &quot;message 1&quot;,
      new: false
    },
    {
      message: &quot;message 2&quot;,
      new: false
    },
    {
      message: &quot;message 3&quot;,
      new: true
    }
  ];
  
  export default function App() {
    const [messages, setMessages] = React.useState(defaultMessages);
    const messagesRef = React.useRef(messages);
  
    messagesRef.current = messages;
  
    // add a new message every 2 seconds
    useInterval(() =&gt; {
      messages.length &lt; 10 &amp;&amp;
        setMessages([
          ...messages,
          { message: `message ${messages.length + 1}`, new: true }
        ]);
    }, 2000);
  
    React.useEffect(() =&gt; {
      const timer = setTimeout(() =&gt; {
        // console.log(&quot;change all messages from new to old&quot;);
        const updateMessages = messagesRef.current.map(m =&gt; ({
          ...m,
          new: false
        }));
        setMessages([...updateMessages]);
      }, 5000); // if you change this to duration less than 2 seconds then it runs just fine
      return () =&gt; clearTimeout(timer); // removing the timer, calls it with every message update and seemingly ignores the timeout duration
    });
  
    return (
      &lt;div className=&quot;App&quot;&gt;
        {messages.map(m =&gt; (
          &lt;div key={m.message}&gt;
            {m.message}, status: {m.new ? &quot;new&quot; : &quot;old&quot;}
          &lt;/div&gt;
        ))}
      &lt;/div&gt;
    );
  }
  </code></pre>
  <p><strong>Example code</strong>: <a href="https://codesandbox.io/s/settimeout-resetting-with-updates-ufl3b" rel="nofollow noreferrer">https://codesandbox.io/s/settimeout-resetting-with-updates-ufl3b</a></p>
  <p>Not sure how to approach this with React Hooks api. The timeouts need to persist, five seconds after every update. Where as right now every timeout seemed to be canceled or queued by the one that comes after it. I'm puzzled.</p>
  <p>Thank you!</p>