use-resize-observer icon indicating copy to clipboard operation
use-resize-observer copied to clipboard

Support React 19

Open osdiab opened this issue 1 year ago • 16 comments

NextJS 15 RC just released which requires react 19.

  • loosen peer dependency versions to allow it
  • check that the library still works as expected with React 19

thanks!

osdiab avatar May 24 '24 04:05 osdiab

Can't promise you anything, but with a little luck I might get to it this weekend. We'll see.

On Fri, 24 May 2024 at 06:22, Omar Diab @.***> wrote:

NextJS 15 RC just released which requires react 19.

  • loosen peer dependency versions to allow it
  • check that the library still works as expected with React 19

thanks!

— Reply to this email directly, view it on GitHub https://github.com/ZeeCoder/use-resize-observer/issues/108, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA4CKESWA2S6UTH5P5KBPN3ZD26AHAVCNFSM6AAAAABIG2PYG6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGMYTIMZRGE4DSMI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

ZeeCoder avatar May 24 '24 06:05 ZeeCoder

I'll wait for a stable release actually.

On Fri, 24 May 2024 at 08:31, Viktor Hubert @.***> wrote:

Can't promise you anything, but with a little luck I might get to it this weekend. We'll see.

On Fri, 24 May 2024 at 06:22, Omar Diab @.***> wrote:

NextJS 15 RC just released which requires react 19.

  • loosen peer dependency versions to allow it
  • check that the library still works as expected with React 19

thanks!

— Reply to this email directly, view it on GitHub https://github.com/ZeeCoder/use-resize-observer/issues/108, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA4CKESWA2S6UTH5P5KBPN3ZD26AHAVCNFSM6AAAAABIG2PYG6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGMYTIMZRGE4DSMI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

ZeeCoder avatar Jun 24 '24 07:06 ZeeCoder

Next 15 just got released as stable and ready for production, and it depends on React 19 which is still release candidate; upon upgrading I found that the typings for the ref prop are failing because of some upstream changes in React typing; this library wants a RefObject<Element> rather than RefObject<Element | null> so if you call useRef() and give it null as a default before the ref is initialized, that ref cannot be passed.

Haven't tested if anything else fails to work.

osdiab avatar Oct 29 '24 06:10 osdiab

Yeah seems like an easy enough fix.

The majority of the work might just be around fixing the type and adding React 19 tests.

Otherwise the code might just work already as-is.

On Tue, Oct 29, 2024, 07:35 Omar Diab @.***> wrote:

Next 15 just got released as stable and ready for production https://nextjs.org/blog/next-15, and it depends on React 19 which is still release candidate; upon upgrading I found that the typings for the ref prop are failing because of some upstream changes in React typing; this library wants a RefObject<Element> rather than RefObject<Element | null> so if you call useRef() and give it null as a default before the ref is initialized, that ref cannot be passed.

Haven't tested if anything else fails to work.

— Reply to this email directly, view it on GitHub https://github.com/ZeeCoder/use-resize-observer/issues/108#issuecomment-2443327691, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA4CKEU3PRAZVVR2WICX3ITZ54UCBAVCNFSM6AAAAABIG2PYG6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINBTGMZDONRZGE . You are receiving this because you commented.Message ID: @.***>

ZeeCoder avatar Nov 01 '24 13:11 ZeeCoder

Fantastic!

Unfortunately I don't have enough time to make a proper release right now.

The test suite needs upgrading so that it could run both 18 and 19, types changed significantly as well, and my gut feel is that the tests will yield some issues.

ZeeCoder avatar Dec 30 '24 14:12 ZeeCoder

@ZeeCoder please do keep us updated with any ETA as to when we can expect react 19 support here.

kamyarkaviani avatar Jan 16 '25 01:01 kamyarkaviani

I'll probably post in this PR as I go: https://github.com/ZeeCoder/use-resize-observer/pull/114

ZeeCoder avatar Mar 07 '25 09:03 ZeeCoder

Is there hope for an update in the near future?

sauron918 avatar Mar 24 '25 22:03 sauron918

A native implementation comes out of the box:

import React, {
    useState,
    useCallback,
    useEffect
} from 'react';

const useSize = <T extends React.RefObject<HTMLDivElement | null>>(target: T) => {
    const [size, setSize] = useState<DOMRect>();

    const updateSize = useCallback(() => {
        if (target.current) {
            const size = target.current.getBoundingClientRect();

            setSize(size);
        }
    }, [target]);

    useEffect(() => {
        const {current} = target;

        updateSize();

        const observer = new ResizeObserver((entries) => {
            if (entries.length > 0) {
                updateSize();
            }
        });

        if (current) {
            observer.observe(current);
        }

        return () => {
            if (current) {
                observer.unobserve(current);
            }

            observer.disconnect();
        };
    }, [target, updateSize]);

    return size;
};

export {useSize};
const target = useRef<HTMLDivElement>(null);
const size = useSize(target); // size.width

monolithed avatar Apr 29 '25 06:04 monolithed

A native implementation comes out of the box:

import React, { useState, useCallback, useEffect } from 'react';

const useSize = <T extends React.RefObject<HTMLDivElement | null>>(target: T) => { const [size, setSize] = useState<DOMRect>();

const updateSize = useCallback(() => {
    if (target.current) {
        const size = target.current.getBoundingClientRect();

        setSize(size);
    }
}, [target]);

useEffect(() => {
    const {current} = target;

    updateSize();

    const observer = new ResizeObserver((entries) => {
        if (entries.length > 0) {
            updateSize();
        }
    });

    if (current) {
        observer.observe(current);
    }

    return () => {
        if (current) {
            observer.unobserve(current);
        }

        observer.disconnect();
    };
}, [target, updateSize]);

return size;

};

export {useSize};

const target = useRef<HTMLDivElement>(null); const size = useSize(target); // size.width

Thanks. Seems to work good (y)

jp1357 avatar May 09 '25 19:05 jp1357

A native implementation comes out of the box:

import React, { useState, useCallback, useEffect } from 'react';

const useSize = <T extends React.RefObject<HTMLDivElement | null>>(target: T) => { const [size, setSize] = useState<DOMRect>();

const updateSize = useCallback(() => {
    if (target.current) {
        const size = target.current.getBoundingClientRect();

        setSize(size);
    }
}, [target]);

useEffect(() => {
    const {current} = target;

    updateSize();

    const observer = new ResizeObserver((entries) => {
        if (entries.length > 0) {
            updateSize();
        }
    });

    if (current) {
        observer.observe(current);
    }

    return () => {
        if (current) {
            observer.unobserve(current);
        }

        observer.disconnect();
    };
}, [target, updateSize]);

return size;

};

export {useSize};

const target = useRef<HTMLDivElement>(null); const size = useSize(target); // size.width

this will break if the ref gets updated. using refs as hook dependency is brittle.

m10 avatar Jun 03 '25 14:06 m10

A native implementation comes out of the box: import React, { useState, useCallback, useEffect } from 'react'; const useSize = <T extends React.RefObject<HTMLDivElement | null>>(target: T) => { const [size, setSize] = useState();

const updateSize = useCallback(() => {
    if (target.current) {
        const size = target.current.getBoundingClientRect();

        setSize(size);
    }
}, [target]);

useEffect(() => {
    const {current} = target;

    updateSize();

    const observer = new ResizeObserver((entries) => {
        if (entries.length > 0) {
            updateSize();
        }
    });

    if (current) {
        observer.observe(current);
    }

    return () => {
        if (current) {
            observer.unobserve(current);
        }

        observer.disconnect();
    };
}, [target, updateSize]);

return size;

}; export {useSize}; const target = useRef(null); const size = useSize(target); // size.width

this will break if the ref gets updated. using refs as hook dependency is brittle.

useRef returns a stable object, and useEffect does not react to changes in its properties. In most scenarios, this code is reliable, and you can safely omit the ref from the dependency array if needed.

monolithed avatar Jun 03 '25 18:06 monolithed

exactly. if target.current changes the effect will not run and the wrong element will be observed

m10 avatar Jun 05 '25 16:06 m10

Here you go — should work, I think.

import React, {
    useState,
    useRef,
    useCallback,
    useEffect
} from 'react';

const useRefSize = () => {
    const [size, setSize] = useState<DOMRect>();
    const observerRef = useRef<ResizeObserver | null>(null);

    const refCallback = useCallback((node: HTMLElement | null) => {
        if (observerRef.current) {
            observerRef.current.disconnect();
            observerRef.current = null;
        }

        if (node) {
            const updateSize = () => {
                const rect = node.getBoundingClientRect();

                setSize(rect);
            };

            updateSize();

            const observer = new ResizeObserver(() => {
                updateSize();
            });

            observer.observe(node);
            observerRef.current = observer;
        }
    }, []);

    return [refCallback, size] as const;
};

monolithed avatar Jun 05 '25 18:06 monolithed

nice. that's much better pattern.

is there a reason why you recreate the resizeobserver on each ref callback call? just disconnect / observe should be enough. A further optimization would even be to reuse the same observer instance for all "instances" of this hook. https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ

The initial size may be determined in a layout effect to prevent unecessary rerenders, size state should not be (re-) set if no change. Having a callback passed to the hook, would be nice for being able to have custom logic on resize.

For some application it is critical to have minimal performance overhead. Resize is a high frequency event.

m10 avatar Jun 11 '25 08:06 m10