# All files / src/hooks useSize.ts

0% Statements 0/14
0% Branches 0/4
0% Functions 0/5
0% Lines 0/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45

     // NOTE: same as in uniprot-website codebase
    import { type MutableRefObject, useCallback, useEffect, useState } from 'react';

    /**
     * given a reference to an actual HTML element, gives us access to its size
     * even through resizes and zoom
     * @param {MutableRefObject<HTMLElement>} ref
     * @returns {Array} tuple - return tuple
     * @returns {DOMRect | null} tuple[0]
     *          DOMRect object with the sizes of the passed ref, or null if no ref
     * @returns {() => void} tuple[1]
     *          Manual refresh function, to call if the size needs to be recomputed
     *          for whatever reason (e.g. content changed)
     */
    function useSize(
      ref: MutableRefObject<Element | null>
    ): [rect: DOMRect | undefined, onResize: () => void] {
      const [rect, setRect] = useState<DOMRect>();

      const onResize = useCallback(() => {
        if (!ref.current) {
          return;
        }
        setRect(ref.current.getBoundingClientRect());
      }, [ref, setRect]);

      // This effect will run after EVERY render
      useEffect(() => {
        // ask for size value until we finally get one
        if (!rect) {
          onResize();
        }
      }); // No dependency array, it's on purpose!

      useEffect(() => {
        onResize(); // first time
        window.addEventListener('resize', onResize);
        return () => window.removeEventListener('resize', onResize);
      }, [ref, onResize]);

      return [rect, onResize];
    }

    export default useSize;