[Typescript] useRef와 Typescript를 같이 사용하는 경우

박기영·2022년 7월 25일
6

Typescript

목록 보기
5/11

useRef

useRef는 current에 어떠한 값을 담고있는 상자를 만드는 React Hook이다.
그 이상 그 이하도 아니다. 예를 들어보자.

const exRef = useRef(1);

위 코드에서 exRef는 그저 1의 값을 담고있는 상자에 불과하다.
우린 current를 통해서 useRef에 있는 값을 사용할 수 있게 된다.

const num = exRef.current; // num = 1

이 사실을 알고, Typescript와 함께 살펴보자.
물론, useRef 자체만으로도 훨씬 더 많은 설명이 필요하지만, Typescript에서의 useRef를 살펴보고싶기 때문에 여기까지만!

useRef + Typescript

3가지의 경우가 있다.

  1. 제네릭 타입이 인자의 타입과 동일한 경우
useRef<T>(initialValue: T): MutableRefObject<T>;

useRef는 MutableRefObject를 반환한다.
Mutable에서 유추할 수 있듯이, current 그 자체를 변경할 수 있다.

  1. 인자의 타입이 null이 허용될 경우
useRef<T>(initialValue: T|null): RefObject<T>;

useRef는 RefObject를 반환한다.
이 경우, current 그 자체를 변경하는 것이 불가능하다.

  1. 제네릭 타입이 undefined(제공하지 않은 경우)인 경우
useRef<T = undefined>(): MutableRefObject<T | undefined>;

MutableRefObject를 반환하지만 타입이 다른 것을 확인할 수 있다.

예시를 통해서 더 자세하게 살펴보자.

예시

const localVarRef = useRef<number>(0);

const handleButtonClick = () => {
  if (localVarRef.current) {
    localVarRef.current += 1;
    console.log(localVarRef.current); // 1
  }
};

위 예시는 1번의 경우와 같다. 제네릭 타입이 number로 명시되어있고, 인자값도 0으로 number 타입이다.
이 때는 current 그 자체를 변경할 수 있기 때문에, 콘솔에는 0에서 1이 증가한 1이 출력된다.
그렇다면 인자값을 null로 변경시켜보겠다.

const localVarRef = useRef<number>(null);

const handleButtonClick = () => {
  if (localVarRef.current) {
    localVarRef.current += 1; // 에러 발생!!!
    console.log(localVarRef.current);
  }
};

위 예시는 2번의 경우와 같다. 제네릭 타입은 number인데, 인자값에 null이 허용되었기 때문이다.
이 때는 current를 직접 변경할 수 없다. 따라서 에러가 발생한다.

이번에는 예시를 변경해보자.

const App = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleButtonClick = () => {
    if (inputRef.current) {
      inputRef.current.value = ""; // 수정 가능!
    }
  };

  return (
    <div className="App">
      <button onClick={handleButtonClick}>+1</button>

      <input ref={inputRef} />
      <button onClick={handleButtonClick}>Clear</button>
    </div>
  );
};

위 코드는 2번의 경우라는 것을 쉽게 알 수 있다.
하지만 이번에는 current를 직접 건드리는게 아닌 current.value를 수정하고 있다.
이 것은 가능하다. 왜 가능할까?
current만 읽기 전용(read only)이기 때문에, current의 하위 프로퍼티인 value는 수정이 가능한 것이다.
이는 읽기 전용이 얕기(shallow) 때문이다.

이번에는 인자값을 지워보겠다.

 const inputRef = useRef<HTMLInputElement>();

위 코드는 3번의 경우이다.
이 때는 MutableRefObject를 반환한다.
결과는...에러가 발생한다!

<input ref={inputRef} /> // 에러 발생!!!

이유가 뭘까?
우리가 흔히 사용하는 컴포넌트를 참조하기 위한 ref에는 RefObject만 넣을 수 있기 때문이다.
MutableRefObject와 RefObject는 엄연히 다르기 때문에 에러가 발생하는 것이다.

결론

만약, 로컬 변수 용도로 useRef를 사용하는 것이라면 MutableRefObject를 사용해야하는 것이므로
다음과 같이 사용하자.

const localRef = useRef<number>(0);

만약, DOM을 직접 조작하기 위해 useRef를 사용할 경우, RefObject를 사용해야하므로
다음과 같이 사용하자.

const inputRef = useRef<HTMLInputElement>(null);

참고 자료

참고 자료 - 정말 이해하기 쉽게 설명해놓으셨다!

profile
나를 믿는 사람들을, 실망시키지 않도록

2개의 댓글

comment-user-thumbnail
2023년 2월 3일

글을 정말 잘 쓰셔서 이해가 쏙쏙 되었어요 덕분에 useRef에 대해 타입스크립트까지 제대로 공부하고 가네요 감사합니다~

1개의 답글