[React X TS] useRef의 3가지 타입

coderH·2023년 2월 25일
0

오늘은 React에서 사용하는 useRef훅에 대해 다뤄보려고 합니다.

useRef 훅은 리액트 애플리케이션에서 DOM에 접근하거나 리렌더링을 유발하지 않는 로컬 변수를 선언할 때 주로 사용합니다.

JS 환경에서는 해당 훅을 사용하면서 에러를 만나기 쉽지 않은데 TS 환경에서는 타입 관련 에러가 발생하는 모습을 종종 볼 수 있습니다.

그래서, useRef 훅을 사용할 때 에러가 발생하는 원인은 무엇인지, 어떻게 사용해야 하는지에 대해서 알아보겠습니다.

에러 발생원인

먼저, React와 관련된 타입이 정의되어 있는 @types/react의 index파일을 들어가보면 useRef는 다음과 같이 3가지 타입을 가진 overloading 메소드로 정의되어 있습니다.

  • overloading 메소드란?
    여러개의 함수가 같은 이름을 가지고 있는것을 말합니다.
    따라서, 호출할 때 인자의 타입이나 개수에 따라 호출되는 함수 로직이 다를 수 있으며
    반환 값 또한 다를 수 있습니다.

위 사진을 살펴보면 useRef훅은 3가지의 타입을 가지고 있으며 반환 값은 MutableRefObject 혹은 RefObject를 반환한다고 작성되어 있습니다.

아시다시피, useRef는 객체를 반환하며 인자로 전달받은 값 또는 ref prop으로 등록했던 해당 DOM객체를 자신이 반환하는 객체의 current 값으로 할당합니다.

그렇다면 useRef가 반환하는 객체들이 어떻게 생겼는지도 알아봐야겠죠?

이 두 객체는 current 속성이 읽기 전용 속성인 readonly가 적용되어 있는지,
또 값으로 null을 받을 수 있는지 없는지에 대한 차이가 있습니다.

일단, 여기까지 다뤘던 내용을 정리해보면 useRef는 인자의 타입에 따라 MutableRefObject 혹은 RefObject 두 가지 타입의 객체가 반환되며

useRef에 인자를 넣거나 인자를 전달하면 MutableRefObject가 반환되고,
null을 넣으면 RefObject 반환된다라고 정리할 수 있습니다.

사실, useRef 훅의 호출 단계에서는 이 차이가 전부입니다.

그럼, 에러가 발생하는 원인은 무엇이였을까요?
해당 원인은 컴포넌트의 ref prop에 의해 발생합니다.

위 사진은 컴포넌트의 ref속성에 대한 타입이며 2번 라인에서 보이듯 ref prop으로 올 수 있는 타입은 LegacyRef혹은 undefined입니다.

또한, LegacyRef의 타입은 RefCallback, RefObject, null, string 타입만 올 수 있다고 표기되어있습니다.

아까전에 useRef는 2가지 타입의 객체를 반환한다고 했는데 그 중 하나인 MutableRefObject 타입이 보이지 않습니다.

바로, 이것이 에러가 발생하던 이유입니다.

컴포넌트의 ref 속성에 할당할 수 있는 타입은 useRef가 반환하는 두 가지 타입의 객체중 RefObject만 가능합니다.

따라서, useRefRefObject를 반환하도록 하려면 인자의 타입이 null과 그 외 요소로 명시되어야 하고
ref객체를 컴포넌트의 ref prop으로 등록할 때는 첫 렌더링 이후 리렌더링 발생 시점에 등록되므로 정의 단계에서는 null을 명시해주어야 합니다.

인자를 null로 전달하지 않으면 MutableRefObject가 반환되며 이는 ref prop으로 사용할 수 없습니다.

그럼, 이제 오늘 다뤘던 내용을 총 정리 해보겠습니다.

총 정리

useRef는 overloading 메소드로서 인자의 타입에 따라 반환값이 다르며 MutableRefObject, RefObject 둘 중 하나의 타입을 가진 객체를 반환한다.

DOM에 접근하기 위해 useRef를 사용하는 경우 ref prop으로 등록하게 되는데
두 타입 중 ref prop으로 전달 가능한 타입은 RefObject밖에 없다.

따라서, DOM에 접근하기 위한 목적이라면 const ref = useRef<DOMType>(null)과 같이 초기 인자를 null로 전달해주어야만한다.

반면, 로컬 변수용으로 사용하고자 한다면 변수 또는 값을 초기 인자로 전달하거나 비워둔채로 정의하면 된다.

0개의 댓글