Library-Framework/React

[React] DOM 선택 시, querySelector 대신 useRef 사용하기

그랴 2022. 10. 24. 17:06

문제 상황

현재 사용자가 위치한 페이지에 따라 메뉴 탭의 색을 바꿔주고 싶었다.

이를 구현하기 위해 내가 생각한 방법은 다음과 같다.

1. 현재 위치한 페이지의 링크 끝에 적힌 탭 이름을 가져온다.

2. 탭 이름을 메뉴 탭의 이름과 비교한다.

3. 탭 이름이 메뉴 탭의 이름과 일치한다면, 색을 바꿔준다.

 

오류

TypeError: Cannot read properties of null (reading 'style')

 

원인

HTML이 렌더링되기 전에 JS가 작동되었기 때문에, style 속성값을 읽어올 수 없어 발생한 문제였다.

 

해결 방법

리액트에서는 DOM을 선택할 때, querySelector가 아닌 useRef를 사용한다고 한다.

 

useRef()

  • .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환한다.
  • JS의 DOM Selector(querySelector, getElementByID)와 비슷하다.
  • useRef 객체 생성 → 선택하고 싶은 DOM에 ref값으로 객체 넣기 → 객체를 통해 수행하고 싶은 작업 설정
  • 모든 컴포넌트는 reference element를 가진다. (리액트에서 해당 컴포넌트를 참조함)
  • ref = { 변수명 }
  • 이 외에도, 현재 저장하고 싶은 값을 re-rendering 없이 저장하고 싶을 때도 사용할 수 있다.

 

 

즉 DOM 선택 시, querySelector 말고 useRef()를 사용해주면 된다. id 대신 ref를 적용해주면 된다.
const KeyNav = () => {
  let currUrl = window.document.location.href;
  let currKeyWord = currUrl.substring(29);

  const spicy = useRef();
  const sweet = useRef();
  const sour = useRef();
  const nutty = useRef();
  const salty = useRef();

  useEffect(() => {
    changeColor();
  });

  const changeColor = () => {
    if (currKeyWord === "spicy") {
      spicy.current.style.color = "#BC1D1B";
    } else if (currKeyWord === "sweet") {
      sweet.current.style.color = "#BC1D1B";
    } else if (currKeyWord === "sour") {
      sour.current.style.color = "#BC1D1B";
    } else if (currKeyWord === "nutty") {
      nutty.current.style.color = "#BC1D1B";
    } else if (currKeyWord === "salty") {
      salty.current.style.color = "#BC1D1B";
    }
  };

  return (
    <Nav>
      <Link
        to="/spicy"
        style={{
          fontWeight: "900",
          color: "black",
          textDecorationLine: "none",
        }}
      >
        <span ref={spicy}>매콤 </span>
      </Link>
      <Link
        to="/sweet"
        style={{
          fontWeight: "900",
          color: "black",
          textDecorationLine: "none",
        }}
      >
        <span ref={sweet}>달콤 </span>
      </Link>
      <Link
        to="/sour"
        style={{
          fontWeight: "900",
          color: "black",
          textDecorationLine: "none",
        }}
      >
        <span ref={sour}>새콤 </span>
      </Link>
      <Link
        to="/nutty"
        style={{
          fontWeight: "900",
          color: "black",
          textDecorationLine: "none",
        }}
      >
        <span ref={nutty}>고소 </span>
      </Link>
      <Link
        to="/salty"
        style={{
          fontWeight: "900",
          color: "black",
          textDecorationLine: "none",
        }}
      >
        <span ref={salty}>짧조름 </span>
      </Link>
    </Nav>
  );
};