use-rect.ts 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. // based on https://gist.github.com/morajabi/523d7a642d8c0a2f71fcfa0d8b3d2846?permalink_comment_id=4688158#gistcomment-4688158
  2. import {
  3. useState, useEffect, RefObject, useCallback,
  4. } from 'react';
  5. type MutableRefObject<T> = {
  6. current: T
  7. }
  8. type EventType = 'resize' | 'scroll'
  9. const useEffectInEvent = (
  10. event: EventType,
  11. useCapture?: boolean,
  12. set?: () => void,
  13. ) => {
  14. useEffect(() => {
  15. if (set) {
  16. set();
  17. window.addEventListener(event, set, useCapture);
  18. return () => window.removeEventListener(event, set, useCapture);
  19. }
  20. }, [event, set, useCapture]);
  21. };
  22. export const useRect = <T extends HTMLDivElement | null>(
  23. reference: RefObject<T>,
  24. event: EventType = 'resize',
  25. ): [DOMRect | undefined, MutableRefObject<T | null>, number] => {
  26. const [rect, setRect] = useState<DOMRect>();
  27. const [screenHeight, setScreenHeight] = useState(window.innerHeight);
  28. const set = useCallback(() => {
  29. setRect(reference.current?.getBoundingClientRect());
  30. }, [reference]);
  31. useEffectInEvent(event, true, set);
  32. const handleResize = useCallback(() => {
  33. setScreenHeight(window.innerHeight);
  34. }, []);
  35. useEffect(() => {
  36. window.addEventListener(event, handleResize);
  37. return () => {
  38. window.removeEventListener(event, handleResize);
  39. };
  40. }, [event, handleResize]);
  41. return [rect, reference, screenHeight];
  42. };