Отслеживание изменения offsetTop в React
Мне необходимо отслеживать изменения высоты (width), ширины (height) и положения (offsetTop) элемента на странице. При изменении этих параметров элемента DOM-дерева, необходимо вызывать onChange. Для width/height работает вот этот код:
import React, { useEffect, useRef } from "react";
const ElementChange = React.memo(({ children, onChange }) => {
const changeRef = useRef();
const observer = useRef();
useEffect(() => {
if (observer.current) observer.current.disconnect();
if (changeRef.current && !!onChange) {
const element = changeRef.current;
observer.current = new ResizeObserver(() => {
onChange({ width: element.clientWidth, height: element.clientHeight });
});
observer.current.observe(element);
}
return () => {
if (observer.current) observer.current.disconnect();
};
}, [changeRef, onChange]);
if (React.Children.toArray(children) > 1)
return null;
return React.cloneElement(children, { ref: changeRef });
});
export default ElementChange;
Как отслеживать изменения offsetTop?
PS Сторонние библиотеки не рассматриваются.
Ответы (1 шт):
Автор решения: posix
→ Ссылка
Пока остановился на таком варианте:
import React, { useEffect, useRef } from "react";
const ElementChange = React.memo(
({ children, delay, onChange, getData, ...props }) => {
const changeRef = useRef();
const interval = useRef();
const data = useRef();
useEffect(() => {
clearInterval(interval.current);
if (changeRef.current && !!onChange && !!getData) {
interval.current = setInterval(() => {
const newData = getData(changeRef.current);
if (JSON.stringify(data.current) !== JSON.stringify(newData)) {
data.current = newData;
if (data.current) onChange(data.current);
}
}, delay);
}
return () => clearInterval(interval.current);
}, [changeRef, onChange, getData]);
if (React.Children.toArray(children) > 1) return null;
return React.cloneElement(children, { ref: changeRef, ...props });
}
);
export default ElementChange;
ElementChange.defaultProps = {
delay: 100,
};
Пример использования:
<ElementChange
getData={(element) => {
const { offsetTop, clientWidth, clientHeight } = element;
return {
top: offsetTop,
width: clientWidth,
height: clientHeight
};
}}
onChange={(s) => console.log(s)}
>
<Item />
</ElementChange>
В Item должен быть forwardRef:
import React from "react";
const Item = React.memo(
React.forwardRef((children, ref, ...props) => {
return (
<div ref={ref} {...props}>
{children}
</div>
);
})
);
export default Item;
Вариант конечно не слишком элегантный, да и точность упирается в delay, но если у кого-нибудь есть идеи интереснее, то буду рад услышать.