🙆

【React / useRef】要素の位置、大きさを取得する

2022/03/13に公開

はじめに

ReactでHTML要素の大きさ(幅、高さ)、位置を取得したい場面があり、そのときの実装メモ。

※ TypeScript を使っています

実装

カスタムフックを作る

// 引数のtargetProperty をDOMRectのもつPropertyに限定する
type DOMRectProperty = keyof Omit<DOMRect, 'toJSON'>;

// RefObjectの型は div, span, p, input などのさまざまなHTML要素に対応できるようにextendsで制限をかけつつ抽象化
export const useGetElementProperty = <T extends HTMLElement>(
  elementRef: RefObject<T>
) => {
  const getElementProperty = useCallback(
    (targetProperty: DOMRectProperty): number => {
      const clientRect = elementRef.current?.getBoundingClientRect();
      if (clientRect) {
        return clientRect[targetProperty];
      }

      // clientRect が undefined のときはデフォルトで0を返すようにする
      return 0;
    },
    [elementRef]
  );

  return {
    getElementProperty,
  };
};
offsetxx と getBoundingClientRect().xx の違い

この書き方でも width を取得できる

elementRef.current?.offsetWidth;

補足

↓これは

type DOMRectProperty = keyof Omit<DOMRect, 'toJSON'>;

↓これと同じこと

type DOMRectProperty =
  | 'height'
  | 'width'
  | 'x'
  | 'y'
  | 'top'
  | 'right'
  | 'bottom'
  | 'left';

Componentで利用する

カスタムフックを呼び出して利用する。

const Home: NextPage = () => {
  const targetRef = useRef(null);
  const { getElementProperty } =
    useGetElementProperty<HTMLDivElement>(targetRef);

   return (
    <div>
      {/*値を取得したい要素にRefをセットする*/}
      <div ref={targetRef}>
        {/*~~~~~~省略~~~~~~*/}
      </div>
    </div>  

取得した値をコンソールに出力してみる

const Home: NextPage = () => {
  const targetRef = useRef(null);
  const { getElementProperty } =
    useGetElementProperty<HTMLDivElement>(targetRef);

  useEffect(() => {
    console.log("height", getElementProperty("height"));
    console.log("width", getElementProperty("width"));
    console.log("x", getElementProperty("x"));
    console.log("y", getElementProperty("y"));
    console.log("top", getElementProperty("top"));
    console.log("right", getElementProperty("right"));
    console.log("bottom", getElementProperty("bottom"));
    console.log("left", getElementProperty("left"));
  }, []);

  return (
    <div>
      {/*値を取得したい要素にRefをセットする*/}
      <div ref={targetRef}>
        {/*~~~~~~省略~~~~~~*/}
      </div>
    </div>

取得できた!

最後に

ありがとうございました!!

参考

Discussion