React의 useRef를 사용하기위한주의 사항

11117 단어 React후크

소개



DOM의 바운딩 박스 등을 취득하는 경우, hooksuseRef 를 사용하고 싶은 경우가 있습니다. 그러나, 하위의 컴퍼넌트에 그러한 정보를 건네주는 경우 등은, 주의가 필요하게 됩니다.



다음과 같이 메시지의 오른쪽 하단에 좋아요 버튼을 표시하고 싶습니다.


작동하지 않는 패턴


ThumbsUp 컴퍼넌트에 대해 버튼 위치의 기준이 되는 HTMLElement 를 건네주어, ThumbsUp 로 버튼의 표시 위치를 요구하고 있습니다.

App.tsx
import React, { useRef } from "react";
import ThumbsUp from "./ThumbsUp";
import "./styles.scss";

export default function App() {
  const ref = useRef<HTMLSpanElement | null>();
  return (
    <div>
      <span ref={ref} className="baloon">
        こんにちは
      </span>
      {ref.current && (
        <ThumbsUp anchor={ref.current} />
      )}
    </div>
  );
}


ThumbsUp.tsx
import React, { useRef, useEffect } from "react";
import "./styles.scss";

type Props = {
  anchor: HTMLElement;
};
export default function Portal({ anchor }: Props) {
  const ref = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    if (ref.current) {
      const anchorRect = anchor.getBoundingClientRect();
      const position = {
        top: anchorRect.top + anchorRect.height - 20,
        left: anchorRect.left + anchorRect.width - 10
      };
      ref.current.style.top = `${position.top}px`;
      ref.current.style.left = `${position.left}px`;
    }
  }, [anchor]);
  return (
    <div ref={ref} className="thumbs-up">
      <button>
        <span role="img" aria-label="thumbs-up">
          👍
        </span>
      </button>
    </div>
  );
}

무슨 일이 일어나는가



불행히도 의도대로 좋아요 버튼이 표시되지 않습니다.

이것은 공식 에도 기재되어 있습니다만, App.tsx 에 있어서, ref.current 가 바뀌어도 재렌더는 발생하지 않기 때문입니다. 따라서 ThumbsUp 는 렌더링되지 않은 상태입니다.

해결책



콜백 식의 refuseState 를 사용하는 것으로 해결할 수 있습니다. 아래와 같이 spanref 에 함수를 주는 것으로, setAnchor 가 불려진 타이밍에 재렌더를 발생시켜, 의도대로 ThumbsUp 를 렌더링 할 수 있게 됩니다.

App.tsx
import React, { useState } from "react";
import ThumbsUp from "./ThumbsUp";
import "./styles.scss";

export default function App() {
  const [anchor, setAnchor] = useState<HTMLSpanElement>();
  return (
    <div>
      <span
        ref={elm => { // コールバック関数を与える
          setAnchor(elm);
        }}
        className="baloon"
      >
        こんにちは
      </span>
      {anchor && <ThumbsUp anchor={anchor} /> }
    </div>
  );
}

좋은 웹페이지 즐겨찾기