오늘은 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
만 가능합니다.
따라서, useRef
가 RefObject
를 반환하도록 하려면 인자의 타입이 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로 전달해주어야만한다.
반면, 로컬 변수용으로 사용하고자 한다면 변수 또는 값을 초기 인자로 전달하거나 비워둔채로 정의하면 된다.