rjray
rjray

Reputation: 6673

How to fix "ResizeObserver loop completed with undelivered notifications"

I'm seeing the following error when I dismiss a particular modal:

Error message from React

This didn't happen when I was using react-router v5, but I've recently updated to v6 due to other requirements and it started happening. Funny thing is, I have a second page that invokes the same dialog and it doesn't trigger the error.

(Note that this is a development environment, not a production build. It might not appear in production, or just go to the console.)

I can't seem to find anything through googling... the closest I get are references to "ResizeObserver - loop limit exceeded". I'm puzzled by this, since it doesn't occur on the other page. To make matters worse, the application is using v3 of Bootstrap (company legacy reasons, I don't have the bandwidth right now to address that).

Any ideas?

Upvotes: 84

Views: 191418

Answers (20)

Vidhanshu borade
Vidhanshu borade

Reputation: 28

I was having a similar issue in Antd Table component while using scroll={{x:"max-content"}}.

After removing this prop, it worked.

Upvotes: 0

Arshia.O
Arshia.O

Reputation: 43

FIXED in MUI (not hide)

  1. Find the problem: The error doesnt give much information, go to the page that this error is happening, comment out different elements and find the broken one. I'm using Material UI and I found that multiline TextFields caused the problem. (it takes time)

  2. Fix it: after tons of try and errors I could fix it by adding minHeight to my TextField, see the code I've added.

    <TextField
      fullWidth
      label="label"
      name="name"
      multiline
      sx={{
        "& textarea": {
          minHeight: "100px",
        },
      }}
    />
    

Upvotes: 1

user1658605
user1658605

Reputation: 71

I came across this thread as I also had the React: ResizeObserver loop completed with undelivered notifications error. I removed fullWidth and set my width to 99%, and that fixed my issue.

<TextField
  sx={{
    "& fieldset": { border: 'none' },
   width: "99%"
  }}
  id="resultBox"
  multiline
  // fullWidth
  variant="outlined"
  value={resultsText}
  inputRef={resultBoxRef}
>
</TextField>

Upvotes: 4

Asghar khan
Asghar khan

Reputation: 1

This issues mostly raised with typography of multiline. if you have it on your screen with full width try removing multiline will fix your problem

Upvotes: 0

krezi
krezi

Reputation: 16

I am using DevExtreme (UI-Framework) for an Angular Application. I was able to fix the issue by using shorter labels and item names for my RadioGroups.

in component.html:

<dxi-item
    [colSpan]="3"
    dataField="dataField"
    editorType="dxRadioGroup"
    [editorOptions]="{ items: myItems, valueExpr: 'key', displayExpr: 'name', layout: 'horizontal' }"
>
    <dxo-label text="ShortLabel needs to be short!"></dxo-label>
</dxi-item>

in component.ts:

myItems = [
  { key: false, name: "true" },
  { key: true, name: "false" },
];

Upvotes: 0

T H
T H

Reputation: 558

This hook solved my problem.

const useHideUnimportantErrors = () => {
useEffect(() => {
    function hideError(e) {
        if (e.message === 'ResizeObserver loop completed with undelivered notifications.') {
            const resizeObserverErrDiv = document.getElementById(
                'webpack-dev-server-client-overlay-div'
            );
            const resizeObserverErr = document.getElementById(
                'webpack-dev-server-client-overlay'
            );
            if (resizeObserverErr) {
                resizeObserverErr.setAttribute('style', 'display: none');
            }
            if (resizeObserverErrDiv) {
                resizeObserverErrDiv.setAttribute('style', 'display: none');
            }
        }
    }

    window.addEventListener('error', hideError)
    return () => {
        window.addEventListener('error', hideError)
    }
}, [])

}

Upvotes: 4

In my case, I was using the TextField component from Material UI with the options minRows and maxRows. However, when the content changed, this caused the component and its parent components to resize. My solution was to remove the minRows and maxRows options and instead use the rows option exclusively.

Upvotes: 1

phoenixstudio
phoenixstudio

Reputation: 2598

If you aren't using ResizeObserver in your code, you shouldn't worry about it, it will not appear in build version of your app.

If you are using ResizeObserver check this to get a better understanding of the causes of the error Observation Errors:

Implementations following the specification invoke resize events before paint (that is, before the frame is presented to the user). If there was any resize event, style and layout are re-evaluated — which in turn may trigger more resize events. Infinite loops from cyclic dependencies are addressed by only processing elements deeper in the DOM during each iteration. Resize events that don't meet that condition are deferred to the next paint

This basically means the event of resize happens before the paint and if you do a resize to something that causes another event (before the paint) you could cause an infinite loop.

You can solve that by delaying "Your resize" so that it happens after the repaint, however if there are multiple resize events some of them will happen before the paint (caused by an old delayed resize).

You can avoid this by de-bouncing events and only doing a reaction to the last one (Cancel all your resizes until the observed element "settles").

Here an example on how to solve this in React

 // Here we are trying to match the size of div to an observed div
 // it will affect the origianl one if it is inside it or next to it...
 const observedDivRef = useRef(null);
 const resizingDelayTimer = useRef(null);
 useEffect(() => {
     const observer = new ResizeObserver(() => {
       clearTimeout(resizingDelayTimer.current);
       resizingDelayTimer.current = setTimeout(() => {
         // check if the observed div is still mounted
         // else this will cause memory leak   
         if (observedDivRef.current) {
      setMatchingDivWidth(observedDivRef.current.clientWidth)
         }
       }, 100)
       
     });
     observer.observe(observedDivRef);
   return () => {
     if (observer && observedDivRef.current) observer.unobserve(observedDivRef.current);
   }
 }, []);    

Upvotes: 15

Azim Uddin Ahamed
Azim Uddin Ahamed

Reputation: 21

I tried all solution , but these all are failed.

  useEffect(() => {
const errorHandler = (e:any) => {
  if (
    e.message.includes(
      "ResizeObserver loop completed with undelivered notifications" ||
        "ResizeObserver loop limit exceeded"
    )
  ) {
    const resizeObserverErr = document.getElementById(
      "webpack-dev-server-client-overlay"
    );
    if (resizeObserverErr) {
      resizeObserverErr.style.display = "none";
    }
  }
};
window.addEventListener("error", errorHandler);
return () => {
  window.removeEventListener("error", errorHandler);
};

}, [])

Upvotes: 0

Muhammad Abdullah
Muhammad Abdullah

Reputation: 31

I realized that LastPass, in its zeal to manage form inputs, was inadvertently intensifying the situation. Each dynamically generated form input was like a new battlefield for ResizeObserver and LastPass, creating a loop of updates that pushed ResizeObserver to its limits. One of the many temporary solution is to disable the LastPass extension from your browser. However, in my sitemaster.js file, I handled this exception this way.

window.alert = function (message) {
const keywordToIgnore = "resizeobserver";

const trimmedMessage = message.trim().toLowerCase();

if (trimmedMessage.includes(keywordToIgnore)) {
    return;
}

swal({
    html: message,
    type: "info",
}).then(
    function () {},
    function () {}
);

};

Upvotes: 0

magic_turtle
magic_turtle

Reputation: 1333

I was able to fix the ResizeObserver completed with undelivered notifications error by writing local ResizeObserver hook (I'm using Typescript with React, react-router v6, react v17), the code is below.

I have a feeling that this error happens if calling ResizeObserver without checking for ref && ref.current.

In the hook, I return only the height and width of contentBoxSize, but you can modify the return to your needs. I'm using ResizeObserver to dynamically adjust the size of the container with a pdf file in it (I didn't include the pdf-related code, only the hook and a parent component).

type ResizeObserverReturnType = {
  height: number | undefined;
  width: number | undefined;
}

// The ResizeObserver hook
export const useResizeObserver = (
  ref: React.MutableRefObject<HTMLDivElement | null>
): ResizeObserverReturnType => {
  const [height, setHeight] = useState<number | undefined>(undefined);
  const [width, setWidth] = useState<number | undefined>(undefined);

  const observer: ResizeObserver = useMemo(() => {
    return new ResizeObserver(([entry]) => {
      const height = entry.contentBoxSize[0].blockSize;
      const width = entry.contentBoxSize[0].inlineSize;
      setHeight(height);
      setWidth(width);
    });
  }, []);

  useEffect(() => {
    if (ref && ref.current) {
      observer.observe(ref.current);
    }
    // Remove the observer as soon as the component is unmounted
    return () => {
      observer.disconnect();
    };
  }, [observer, ref]);

  return { height, width };
};

And then in my component I use this hook by providing a ref to it:

type Props = {
  testValue: string;
};
export const YourContainer: React.FC<Props> = props => {
  // Create ref
  const ref = useRef<HTMLDivElement | null>(null);
  // Pass ref to observer
  const { height = 1, width = 1 } = useResizeObserver(ref);

  // Connect ref to your container
  return (
    <StyledContainer ref={ref}>
      {
        // Render a component that is changing in size
        // Pass required width and/or height
        <YourComponent width={width} height={height} />
      }
    </StyledContainer>
  );
};

Upvotes: 0

Lev
Lev

Reputation: 1

I had the same issue using SyncFusion's RichTextEditor. Whenever I wrote enough characters so that the editor grew, and then deleted some lines, it resized and this error was fired.

Figured out it wasn't because of React or because of the component itself, but because I was using Firefox with the extension "LanguageTool", a grammar checker (thus observing textareas...).

If someone else is having the same issue, try using another navigator and maybe disable your plugins; one of them might be the culprit...

Upvotes: 0

esmoley
esmoley

Reputation: 499

For me the issue happens with Cascader from Ant design and only in webpack dev server. Sujen's solution works, but it is a kill switch from all the webpack errors. There is more elegant way to hide them optionally on the webpack side. Edit file webpack.config.js to hide runtimeErrors only:

module.exports = { 
  //...
  devServer: {
    client: {
      overlay: {
        runtimeErrors: false,
      },
    },
  },
};

or even better - forward the error to the console:

module.exports = {
  //...
  devServer: {
    client: {
      overlay: {
        runtimeErrors: (error) => {
          if(error?.message === "ResizeObserver loop completed with undelivered notifications.")
          {
             console.error(error)
             return false;
          }
          return true;
        },
      },
    },
  },
};

Upvotes: 8

T H
T H

Reputation: 558

In my case, I just need to set the min-width for the body element in the "index.css" file.

body {
    min-width: 400px;
}

Upvotes: 0

darksoulsong
darksoulsong

Reputation: 15319

I had this issue due to an expensive callback function and a few DOM changes happening in quick succession. Debouncing it fixed the problem.

 useEffect(() => {
    const observeTarget = ref.current;
    if (!observeTarget) return;

    const debouncedCallback = debounce((entry) => {
      setElementSize({ width: entry.contentRect.width, height: entry.contentRect.height });
      if (callback && typeof callback === 'function') {
        callback(entry.contentRect);
      }
    }, debounceTime);

    const resizeObserver = new ResizeObserver((entries) => {
      if (!Array.isArray(entries) || !entries.length) return;

      const entry = entries[0];
      debouncedCallback(entry);
    });

    resizeObserver.observe(observeTarget);

    return () => resizeObserver.unobserve(observeTarget);
  }, [ref, callback, debounceTime]);

Upvotes: 0

Stas
Stas

Reputation: 305

You can find an explanation for this exact error in the documentation

https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors

So from my understanding, that error means that you have a case when the browser got so many resize events that it doesn't have a chance for an actual repaint, even though the layout has been changed. I fixed that problem by wrapping callback with debounce from Lodash with 0 timeout.

new ResizeOserver(debounce((entries) => {
  for (const entry of entries) {
     // enter code here
  }
}))

Upvotes: 8

McGooks
McGooks

Reputation: 57

I had encountered this issue, upon further investigation of my code it turned out that, even though, I had updated to the latest version of React, I hadn't refactored the JS in my App.js file.

I simply resolved by updating my App.js file to the below

const container = document.getElementById("root");
const root = createRoot(container!);

root.render(<App />);

Upvotes: 1

Sujen
Sujen

Reputation: 278

Add the below line to your main CSS file like app.css or app.scss

iframe#webpack-dev-server-client-overlay{display:none!important}

Upvotes: 6

Vic
Vic

Reputation: 319

I've stumbled upon a similar problem, though not quite related to react-router per se.

The specs say that this happens in case of infinite resize loops as it's displayed here.

To prevent this from happening, we've figured out using a cunning mediator function, which utilizes window.requestAnimationFrame() to render things properly.

Typescript code:

    const observerCallback: ResizeObserverCallback = (entries: ResizeObserverEntry[]) => {
      window.requestAnimationFrame((): void | undefined => {
        if (!Array.isArray(entries) || !entries.length) {
          return;
        }
        yourResizeHandler();
      });
    };
    const resizeObserver = new ResizeObserver(observerCallback);

Upvotes: 21

rjray
rjray

Reputation: 6673

The dialog in question was rendering a form, and by removing one element at a time I was able to determine that one specific text-entry field was causing the issue.

The problem stemmed from the LastPass browser extension trying to provide the option of auto-fill for that field. If I shortened the width of the field, it no longer caused the error. If I disabled the LP auto-fill icon from appearing, it also solved the issue. I chose the latter, since this was not something that LP could really auto-fill anyway.

I don't know why this only triggered when I upgraded from v5 to v6 of react-router-dom. Our staging and production instances that have not yet received the upgraded code work fine with the LP icon present in the field. Nonetheless, the issue is fixed for me.

Upvotes: 63

Related Questions