Do you want to request a feature or report a bug?
Bug
What is the current behavior?
In chrome, does not seem to fire if the image is there on the initial server side html but it fires on both Safari and Firefox.
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. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
An example can be seen here: https://github.com/MWGitHub/ssr-skeleton
Pull down the repo npm i, npm run dev and go to localhost:3000.
There should be a console log when the image is loaded.
This does not occur in Chrome but you can see the log in Safari and Firefox.
Changing the file src/ClientRoot.jsx from ReactDOM.hydrate to ReactDOM.render causes img onLoad to trigger properly.
What is the expected behavior?
The expected behavior is for onLoad to fire on images that are in the initial server side html.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Browsers: Chrome in OS X El Capitan
React versions: React 16.3.X, React 16.2
Would you like to look into why this happens?
Sure I'll dig deeper into it when I have more time.
I took a look at this as it's related to something I'm working on right now. Without diving into the internals of react or react-dom too much, the problem seems reasonably straightforward:
Since server-side rendered html is passed to the web browser as part of the static html file it loads, any img tags that were rendered with a valid src attribute server-side can immediately start loading their content. If that content finishes loading before ReactDOM hydrates, then the native onload event fires before React has connected any listeners to the element. As an example, the following modification will cause the onload message to never display in any browser, assuming the image is fetched within 10 seconds:
setTimeout(() => ReactDOM.hydrate(/* ... */), 10000)
The reproducing example puts the client side javascript in a script tag at the bottom of the body, which means that the browser will have seen the image tag and possibly started loading it before executing any javascript. Is there any reason to expect this to work? I got flaky behavior trying this from both Chrome 65 and Firefox 59 on Windows, and it makes sense that a web browser could have the image loaded before the rest of the page had finished loading, since the image load would only need to beat out the javascript file load.
The example works when hydrate is replaced with render because render tears down the content that existed inside the destination element, and onload will then fire for the new img that was created.
Right, it makes sense for the browser load event to fire before and React missing it since hydrate will not tear down the content and rerender. In my example the img portion of the content is also unchanged when state was updated later either so it makes sense that onLoad wouldn't fire. I think the differences in browsers onLoad may have been mostly from timing.
Having react's onLoad not fire on hydrate due to the image already being loaded does keep with the standard expectations of how onload works normally.
It looks like I'll have to use another approach for images when using hydrate instead.
Closing this, onLoad is behaving as expected and it's timing issues that's causing different behavior at times.
Most helpful comment
I took a look at this as it's related to something I'm working on right now. Without diving into the internals of react or react-dom too much, the problem seems reasonably straightforward:
Since server-side rendered html is passed to the web browser as part of the static html file it loads, any img tags that were rendered with a valid src attribute server-side can immediately start loading their content. If that content finishes loading before ReactDOM hydrates, then the native onload event fires before React has connected any listeners to the
element. As an example, the following modification will cause the onload message to never display in any browser, assuming the image is fetched within 10 seconds:
The reproducing example puts the client side javascript in a script tag at the bottom of the body, which means that the browser will have seen the image tag and possibly started loading it before executing any javascript. Is there any reason to expect this to work? I got flaky behavior trying this from both Chrome 65 and Firefox 59 on Windows, and it makes sense that a web browser could have the image loaded before the rest of the page had finished loading, since the image load would only need to beat out the javascript file load.
The example works when
hydrateis replaced withrenderbecauserendertears down the content that existed inside the destination element, andonloadwill then fire for the new img that was created.