Get elements top offset related to window

Viewed 892

I am trying to implement hook that would return offsetTop of an element. This is needed to apply some styles to header it sticks to top.

import { useState, useEffect } from 'react';

interface ElementPosition {
    left: number | undefined;
    right: number | undefined;
    top: number | undefined;
    bottom: number | undefined;
}

export const useElementPosition = (ref: any): ElementPosition => {
    const [position, setPosition] = useState<ElementPosition>({
        left: undefined,
        right: undefined,
        top: undefined,
        bottom: undefined,
    });

    useEffect(() => {
        if (ref.current) {
            setPosition({
                top: ref.current.offsetTop,
                bottom: ref.current.offsetBottom,
                left: ref.current.offsetLeft,
                right: ref.current.offsetRight,
            });
        }
    }, [ref.current]);

    return position;
};

But now I remembered that ref.current change does not trigger useEffect so I am able to get initial offset only. Is there any way to do this in reusable way like hooks?

1 Answers

For that scenario, you can use a callback ref instead. The callback will be called when the ref gets attached to a new node.

export const useElementPosition = () => {
    const [position, setPosition] = useState<ElementPosition>({
        left: undefined,
        right: undefined,
        top: undefined,
        bottom: undefined
    });

    const ref = useCallback((node) => {
        if (node !== null) {
            setPosition({
                top: node.offsetTop,
                bottom: node.offsetBottom,
                left: node.offsetLeft,
                right: node.offsetRight
            });
        }
    }, []);

    return [position, ref];
}

In this case, rather than passing a ref to the custom hook, you'd return the ref to use from it.

const PositionExample = () => {
    const [position, ref] = useElementPosition();
    console.log(position.top);
    return (
        <h1 ref={ref}>Hello world!</h1>
    );
};

For more details check the official docs: React Hooks - How can I measure a DOM node?.

Related