<p dir="auto">This is a bug. I've spent a lot of time trying to localize the bug and have ended with the following minimal example:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import {useState} from React;

function App() {
  const [imageURL, setImageURL] = useState('https://picsum.photos/1600/1200');
  const [meaninglessValue, setMeaninglessValue] = useState(0);
  
  return (
    &lt;div&gt;
      &lt;p&gt;
        &lt;button onClick={() =&gt; setImageURL('https://picsum.photos/1600/1200')}&gt;Set picture 1&lt;/button&gt;
        &lt;button onClick={() =&gt; setImageURL('https://picsum.photos/1500/1300')}&gt;Set picture 2&lt;/button&gt;
        &lt;button onClick={() =&gt; setMeaninglessValue(meaninglessValue + 1)}&gt;Change another image prop&lt;/button&gt;
      &lt;/p&gt;
      &lt;DelayedImage src={imageURL} unused={meaninglessValue} /&gt;
    &lt;/div&gt;
  );
}

function DelayedImage({src}) {
  const [previousSrc, setPreviousSrc] = useState();
  const [isLoaded, setIsLoaded] = useState(false);

  console.log('Image is rendered with', {previousSrc, src, isLoaded});
  
  if (src !== previousSrc) {
    setPreviousSrc(src);
    setIsLoaded(false);
    console.log('Image unloaded');
  }
  
  const handleLoad = () =&gt; {
    setIsLoaded(true);
    console.log('Image loaded');
  };
  
  return (
    &lt;img
      src={src}
      alt=&quot;&quot;
      onLoad={handleLoad}
      onError={handleLoad}
      style={{
        maxWidth: '100%',
        maxHeight: '80vh',
        opacity: isLoaded ? 1 : 0.2
      }}
     /&gt;
  );
}

ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">useState</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-v">React</span><span class="pl-kos">;</span>

<span class="pl-k">function</span> <span class="pl-v">App</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">imageURL</span><span class="pl-kos">,</span> <span class="pl-s1">setImageURL</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span><span class="pl-kos">(</span><span class="pl-s">'https://picsum.photos/1600/1200'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">meaninglessValue</span><span class="pl-kos">,</span> <span class="pl-s1">setMeaninglessValue</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  
  <span class="pl-k">return</span> <span class="pl-kos">(</span>
    <span class="pl-c1">&lt;</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
      <span class="pl-c1">&lt;</span><span class="pl-ent">p</span><span class="pl-c1">&gt;</span>
        <span class="pl-c1">&lt;</span><span class="pl-ent">button</span> <span class="pl-c1">onClick</span><span class="pl-c1">=</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">setImageURL</span><span class="pl-kos">(</span><span class="pl-s">'https://picsum.photos/1600/1200'</span><span class="pl-kos">)</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>Set picture 1<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">button</span><span class="pl-c1">&gt;</span>
        <span class="pl-c1">&lt;</span><span class="pl-ent">button</span> <span class="pl-c1">onClick</span><span class="pl-c1">=</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">setImageURL</span><span class="pl-kos">(</span><span class="pl-s">'https://picsum.photos/1500/1300'</span><span class="pl-kos">)</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>Set picture 2<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">button</span><span class="pl-c1">&gt;</span>
        <span class="pl-c1">&lt;</span><span class="pl-ent">button</span> <span class="pl-c1">onClick</span><span class="pl-c1">=</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">setMeaninglessValue</span><span class="pl-kos">(</span><span class="pl-s1">meaninglessValue</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>Change another image prop<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">button</span><span class="pl-c1">&gt;</span>
      <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">p</span><span class="pl-c1">&gt;</span>
      <span class="pl-c1">&lt;</span><span class="pl-ent">DelayedImage</span> <span class="pl-c1">src</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">imageURL</span><span class="pl-kos">}</span> <span class="pl-c1">unused</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">meaninglessValue</span><span class="pl-kos">}</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span>
    <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
  <span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-v">DelayedImage</span><span class="pl-kos">(</span><span class="pl-kos">{</span>src<span class="pl-kos">}</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">previousSrc</span><span class="pl-kos">,</span> <span class="pl-s1">setPreviousSrc</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">isLoaded</span><span class="pl-kos">,</span> <span class="pl-s1">setIsLoaded</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span><span class="pl-kos">(</span><span class="pl-c1">false</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

  <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'Image is rendered with'</span><span class="pl-kos">,</span> <span class="pl-kos">{</span>previousSrc<span class="pl-kos">,</span> src<span class="pl-kos">,</span> isLoaded<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  
  <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">src</span> <span class="pl-c1">!==</span> <span class="pl-s1">previousSrc</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-s1">setPreviousSrc</span><span class="pl-kos">(</span><span class="pl-s1">src</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-s1">setIsLoaded</span><span class="pl-kos">(</span><span class="pl-c1">false</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'Image unloaded'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  
  <span class="pl-k">const</span> <span class="pl-en">handleLoad</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-s1">setIsLoaded</span><span class="pl-kos">(</span><span class="pl-c1">true</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'Image loaded'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">;</span>
  
  <span class="pl-k">return</span> <span class="pl-kos">(</span>
    <span class="pl-c1">&lt;</span><span class="pl-ent">img</span>
      <span class="pl-c1">src</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">src</span><span class="pl-kos">}</span>
      <span class="pl-c1">alt</span><span class="pl-c1">=</span><span class="pl-s">""</span>
      <span class="pl-c1">onLoad</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-en">handleLoad</span><span class="pl-kos">}</span>
      <span class="pl-c1">onError</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-en">handleLoad</span><span class="pl-kos">}</span>
      <span class="pl-c1">style</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-kos">{</span>
        <span class="pl-c1">maxWidth</span>: <span class="pl-s">'100%'</span><span class="pl-kos">,</span>
        <span class="pl-c1">maxHeight</span>: <span class="pl-s">'80vh'</span><span class="pl-kos">,</span>
        <span class="pl-c1">opacity</span>: <span class="pl-s1">isLoaded</span> ? <span class="pl-c1">1</span> : <span class="pl-c1">0.2</span>
      <span class="pl-kos">}</span><span class="pl-kos">}</span>
     <span class="pl-c1">/</span><span class="pl-c1">&gt;</span>
  <span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-v">ReactDOM</span><span class="pl-kos">.</span><span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-c1">&lt;</span><span class="pl-ent">App</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">,</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementById</span><span class="pl-kos">(</span><span class="pl-s">'root'</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto"><a href="https://codepen.io/TheFinesse/pen/qgGBqj?editors=0010" rel="nofollow">Live demo</a></p>
<p dir="auto"><strong>Steps to reproduce:</strong></p>
<ol dir="auto">
<li>Open the demo</li>
<li>Wait until the image is loaded (becomes opaque)</li>
<li>Click the "Set picture 2" button</li>
<li>Wait a bit (while the image is loading)</li>
</ol>
<p dir="auto"><strong>Expected result:</strong></p>
<p dir="auto">The second image gets opaque after a few seconds (the <code class="notranslate">DelayedImage</code> component gets rerendered with the new state).</p>
<p dir="auto"><strong>Actual result:</strong></p>
<p dir="auto">The image stays translucent despite the new state that should make it opaque.</p>
<p dir="auto">I reproduced the bug with React 16.8.2 in Safari 12.0.3 and Chrome 72.0.3626.109 on macOS 10.14.3 (didn't try other versions).</p>
<h3 dir="auto">More details about the example</h3>
<p dir="auto">The <code class="notranslate">DelayedImage</code> component is an image that gets translucent while being loaded. The information about whether the image is loading or loaded is stored in a state using the <code class="notranslate">useState</code> hook. The other state hook is used to check whether the image URL has changed (like in <a href="https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops" rel="nofollow">the FAQ example</a>).</p>
<p dir="auto">When the component is rendered for the first time, it works as expected: it is translucent while the image is loading and opaque after the image is loaded. When the <code class="notranslate">src</code> prop is changed (by clicking the "Set picture 2" button), the image gets translucent but doesn't get opaque when it's loaded.</p>
<p dir="auto">According to the console messages, the correct value (<code class="notranslate">isLoaded === true</code>) is set to the state but React doesn't rerenders the component. React rerenders the component with the correct state when any other <code class="notranslate">DelayedImage</code> props is changed (by clicking the last button or changing a prop using Redux Dev Tools).</p>
<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong><br>
Bug</p>
<p dir="auto"><strong>What is the current behavior?</strong><br>
When updating the state from <code class="notranslate">useState</code> doesn't actually update the component. In this case it is being updated on an event handler. I used <code class="notranslate">console.log</code> to verify that it is being called yet no update in the component is being dispatched. It's like React doesn't register that it wants to update the state.</p>
<p dir="auto">Might want to throw out that I'm new with this React Hooks and it could be something that I'm missing.</p>
<p dir="auto"><strong>If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React.</strong><br>
I've setup a simple example showcasing my issue, I also included an implementation with the old class syntax and when doing it with classes, it works fine. <a href="https://codesandbox.io/s/mjz3o5xnly" rel="nofollow">Here is the link to the CodeSandbox</a></p>
<p dir="auto">This example is taken from my project, I'm fading out and translating upwards so I want to keep the text until the animation is done.</p>
<p dir="auto"><strong>What is the expected behavior?</strong><br>
The component should update with the new registered state when trying to update state in a event handler.</p>
<p dir="auto"><strong>Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?</strong><br>
React v16.8<br>
React DOM v16.8</p>