react: Bug: renders twice in firefox with react 18

React version: 18.2.0

Steps To Reproduce

  1. Insert a tag <img/> with src
  2. Go to Firefox inspect tool to the tab network
  3. Reload the page and watch image request in network

Link to code example: https://codesandbox.io/s/unruffled-jerry-9hli44?file=/src/App.js

The current behavior

There are two request for image in firefox, image renders twice image

The expected behavior

There is one request and one render in firefox

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 19
  • Comments: 20

Most upvoted comments

There is, check https://codesandbox.io/s/unruffled-jerry-9hli44?file=/src/index.js On Edge and Firefox I still getting 2 requests, disabling strict-mode it stops.

It really is an issue. Where can we find the root cause of this problem?

We are observing the same behaviour. Firefox 115, Ubuntu Linux 23.04 and macOs. Unable to test on Windows yet.

Here is some details.

The first request is initiated in react-dom.development.js, line 855:

node.setAttribute("src", "https://.../korgi-na-trave-960x540-1-960x540.jpg");

Here is the stack trace.

setValueForProperty           react-dom.development.js:855:12
setInitialDOMProperties       react-dom.development.js:9720:26
setInitialProperties          react-dom.development.js:9921:26
finalizeInitialChildren       react-dom.development.js:10950:23
completeWork                  react-dom.development.js:22193:40
completeUnitOfWork            react-dom.development.js:26596:16
performUnitOfWork             react-dom.development.js:26568:23
workLoopSync                  react-dom.development.js:26466:22
renderRootSync                react-dom.development.js:26434:7
performConcurrentWorkOnRoot   react-dom.development.js:25738:74
...

The second request is initiated here:

function commitMount(domElement, type, newProps, internalInstanceHandle) {
  // Despite the naming that might imply otherwise, this method only
  // fires if there is an `Update` effect scheduled during mounting.
  // This happens if `finalizeInitialChildren` returns `true` (which it
  // does to implement the `autoFocus` attribute on the client). But
  // there are also other cases when this might happen (such as patching
  // up text content during hydration mismatch). So we'll check this again.
  switch (type) {
    case 'button':
    case 'input':
    case 'select':
    case 'textarea':
      if (newProps.autoFocus) {
        domElement.focus();
      }

      return;

    case 'img':
      {
        if (newProps.src) {
          domElement.src = newProps.src; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HERE
        }

        return;
      }
  }
}
commitMount                       react-dom.development.js:11038
commitLayoutEffectOnFiber         react-dom.development.js:23407
commitLayoutMountEffects_complete react-dom.development.js:24688
commitLayoutEffects_begin         react-dom.development.js:24674
commitLayoutEffects_begin         react-dom.development.js:24656
commitLayoutEffects               react-dom.development.js:24612
commitRootImpl                    react-dom.development.js:26823
commitRoot                        react-dom.development.js:26682
finishConcurrentRender            react-dom.development.js:25981
performConcurrentWorkOnRoot       react-dom.development.js:25809
...

node, in the first snippet, and domElement, in the 2nd, are the very same variable: the real <img> DOM node.

The point is the browser is replacing the source of the imgage twice. If the first request has not been completed when the src attribute is set the second time, the browser aborts the first request, leading to the NS_BINDING_ABORTED error. This occurs despite the src value is the same both time.

Note that the src is always converted to a fully qualified URL (have a look : https://github.com/facebook/react/commit/f0dd459e0d97081cb3c313ec52285e3e422f8dbf):

const n = document.createElement("img");
n.src = "/favicon.ico"
console.log(n.src); // prints https://wherever.you.are/favicon.ico

This behaviour has been introduced in https://github.com/facebook/react/commit/086fa8ee2f80f0dc34b7d145be72f9843fca975d

Using Chromium, the request is only initated once, at the very end of the process.

It really happens, even on Chrome/Edge. But I think this is due to StrictMode. Could please try deleting StrictMode on index.js?

It will look like this.

root.render(<App />);

On StrictMode react render twice. https://reactjs.org/docs/strict-mode.html

StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them

@MiguelMachado-dev, Just check this example (without StrictMode): https://codesandbox.io/s/goofy-stonebraker-pf0wg7?file=/src/index.js (https://pf0wg7.csb.app/)

And there is screenshot with two requests:

image

What i’m doing wrong?

It really happens, even on Chrome/Edge. But I think this is due to StrictMode. Could please try deleting StrictMode on index.js?

It will look like this.

root.render(<App />);

On StrictMode react render twice. https://reactjs.org/docs/strict-mode.html

StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them

it doesn’t help, in my example in codesandbox I tried to remove StrictMode, but the behavior is the same, there are two requests in network tab Аnd on Chrome, if you open this https://c1i5n8.csb.app/ there are no two requests in network tab