no-leaked-resize-observer
Enforces that every 'ResizeObserver' created in a component or custom hook has a corresponding 'ResizeObserver.disconnect()'.
Full Name in eslint-plugin-react-web-api
react-web-api/no-leaked-resize-observerFull Name in @eslint-react/eslint-plugin
@eslint-react/web-api-no-leaked-resize-observerPresets
web-api
recommended
recommended-typescript
recommended-type-checked
strict
strict-typescript
strict-type-checked
Rule Details
Creating a ResizeObserver without disconnecting it can lead to memory leaks and unexpected behavior.
Examples
Creating ResizeObserver without disconnecting in useEffect
import React, { useEffect, useRef } from "react";
function MyComponent() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!ref.current) return;
// Problem: A 'ResizeObserver' in 'useEffect' should have a corresponding 'resizeObserver.disconnect()' in its cleanup function.
const ro = new ResizeObserver(() => console.log("resize"));
ro.observe(ref.current);
}, []);
return <div ref={ref} />;
}Disconnecting ResizeObserver in useEffect cleanup
import React, { useEffect, useRef } from "react";
function MyComponent() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!ref.current) return;
// Recommended: Create and use ResizeObserver
const ro = new ResizeObserver(() => console.log("resize"));
ro.observe(ref.current);
// Recommended: Disconnect in the cleanup function
return () => ro.disconnect();
}, []);
return <div ref={ref} />;
}Observing multiple elements with ResizeObserver
When observing multiple elements, disconnect the observer in the cleanup function to prevent memory leaks.
// Recommended: Disconnect ResizeObserver when observing multiple elements
import { useEffect, useRef } from "react";
function ResizablePanels() {
const panelARef = useRef<HTMLDivElement>(null);
const panelBRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const ro = new ResizeObserver((entries) => {
for (const entry of entries) {
console.log("Size changed:", entry.contentRect);
}
});
if (panelARef.current) ro.observe(panelARef.current);
if (panelBRef.current) ro.observe(panelBRef.current);
return () => ro.disconnect();
}, []);
return (
<>
<div ref={panelARef}>Panel A</div>
<div ref={panelBRef}>Panel B</div>
</>
);
}Versions
Resources
Further Reading
See Also
react-web-api/no-leaked-event-listener
Enforces that everyaddEventListenerin a component or custom hook has a correspondingremoveEventListener.react-web-api/no-leaked-fetch
Enforces that everyfetchin a component or custom hook has a correspondingAbortControllerabort in the cleanup function.react-web-api/no-leaked-interval
Enforces that everysetIntervalin a component or custom hook has a correspondingclearInterval.react-web-api/no-leaked-timeout
Enforces that everysetTimeoutin a component or custom hook has a correspondingclearTimeout.