티스토리 뷰

Typescript에서 useRef를 사용할 때에는 용도에 따라서 타입지정이 달라지게 되는데 크게 두 가지로 나눌 수 있다.

 

1. 값 저장 용도 (current 객체 자체를 수정하기 위함)

: useRef를 로컬 변수 용도로 사용하는 경우이다. 

  • 제네릭: 값의 타입을 넣어준다.
  • 초기값: 타입에 맞는 초기값을 할당해준다.
const count = useRef<number>(0);
const text = useRef<string>("")

2. DOM 취득 용도

  • 제네릭: 참조하는 HTML 엘리먼트를 넣어준다.
  • 초기값: null을 넣어준다. 
// DOM button 참조: 제네릭으로 html엘리먼트(button) 설정. 초기값은 null로 설정
const buttonRef = useRef<HTMLButtonElement>(null);

// DOM input 참조 : 제네릭으로 html엘리먼트(input) 설정
const inputRef = useRef<HTMLInputElement>(null);

useRef - ref 객체 타입

1. 값 저장 용도: ref객체.current의 값을 수정 가능

React.MutableRefObject<제네릭>

2. DOM 취득 용도

ref 객체는 React.RefObject<제네릭> 타입이 되며, ref.current(참조하는 DOM)값 자체는 수정 불가

단, ref.current.속성(DOM객체.속성)은 수정이 가능하다.

Q. useRef는 수정 불가능한 RefObject<T>를 반환하는데, 왜 inputRef.current.value는 수정이 가능할까?
A. 정의상 current 프로퍼티만 readonly로, current 프로퍼티의 하위 프로퍼티인 value는 여전히 수정 가능하다. 
readonly가 shallow하기 때문이다. 
React.RefObject<HTMLButtonElement>
React.RefObject<HTMLInputElement>

결론

1번의 예시가 잘 와닿지 않아 찾아보니 useRef로 컴포넌트 안의 변수를 만들면 리렌더링을 발생하지 않고 초기화되지 않는 값을 관리할 수 있다고 한다.(heap 영역에 저장되는 일반적인 JS객체이기 때문에 react가 변경사항을 감지할 수 없다)

  • 사용예시: setTimeout, setInterval의 id, 외부 라이브러리를 사용하여 생성된 인스턴스 scroll 위치 등 그냥 순수 JS로 렌더링마다 초기화되지 않는 변수가 필요할 때 사용하면 될 듯하다.

 

내가 주로 react 에서 useRef를 사용했던 상황은 주로 돔 요소를 가져와 focus를 주는 등.. 이 경우는 2번에 해당한다. 

비제어 컴포넌트는 역시 2번을 활용하는 거 같다. 

기능 제어 컴포넌트 비제어 컴포넌트
일회성 정보 검색 (예: 제출) O O
제출 시 값 검증 O O
실시간으로 필드값의 유효성 검사 O X
조건부로 제출 버튼 비활성화 (disabled) O X
실시간으로 입력 형식 적용하기 (숫자만 가능하게 등) O X
동적 입력 O X

all ref: 

 

TypeScript React에서 useRef의 3가지 정의와 각각의 적절한 사용법

Type 'MutableRefObject<... | undefined>' is not assignable to type ... 에러 좀 그만 보자!

driip.me

댓글