React useRef에 대하여

Posted by , January 15, 2023
React
Series ofReact

thumbnail

개인적인 스터디를 하다가...

Typescript에서 useRef에 대한 사용법을 조사하다...
좀 딥하게(?) 약간은 좀 알아보고자 찾고 학습한 내용을 포스팅으로 정리해봤다.

역시 매번 느끼는데 웹 문서 스크롤로 몇번 내리고 예제 몇번 해보면 되는데,
이걸 문서화 하는건 역시 시간이 든다.
하지만 이렇게 함으로써 머리속에서 정리가 되고 내 경험치가 쌓이겠지... 라는 위안으로 포스팅을 시작해본다.

UseRef?

뭐 알다시피 React Hook의 일종이다.
함수의 형태는 다음과 같이 생겼다.

function useRef<T>(initialValue: T): MutableRefObject<T> //1
function useRef<T>(initialValue: T | null): RefObject<T> //2
function useRef<T = undefined>(): MutableRefObject<T | undefined> //3

저것에 대해서는 차차 알아보고 저렇게 생겼다는 것을 알아두자.
.current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환한다.

말이 뭔가 어려운데 쉽게 DOM 객체를 조작하거나, 컴토넌트의 특정 부분을 선택할 수 있는 방법을 제시하는 Hook이다.
그래서 간단한 사용 예시는...
코드를 보자

export default function SomeComponent() {
  const inputRef = useRef<HTMLInputElement>(null)

  return (
    <>
      <div className="App">
        <div>Hi</div>
        <input placeholder="hello" ref={inputRef} />
        <button onClick={() => console.log("a = ", inputRef.current?.value)}>
          Check
        </button>
      </div>
    </>
  )
}

예제 코드가 좀 엉망이지만 input에 값을 입력하고 버튼을 클릭하면,
콘솔에 input의 입력 값이 나오게 된다.

여기서도 한 가지 중요 포인트는 이 .current로 변경시킬 때 리랜더링을 발생시키지 않는다 라는 점을 유의해야 한다.
그래서 어떤 가변적인 값을 유지하기에 좋다.
공홈에도 이렇게 명시되어 있다.

본질적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 “상자”와 같습니다.

무튼 돌아와서...
위의 선언된 useRef를 보면 반환 값이 MutableRefObjectRefObject 이렇게 두 가지로 되어 있다.

먼저 답을 이야기 하면...

MutableRefObject는 로컬 변수 용도로... 즉 값 형태로 사용할 때 쓰는 타입이고,
RefObject는 DOM 객체를 담을 때 쓰는 타입이다.

자세한 것은 각각 타입을 설명하면서 다루겠다.


MutableRefObject

이름만 봐도 알 수 있다.
변형적인 Ref 객체...(너무 원시적인가 -_-;;)

무튼 변수와 같은 값을 담는 참조 객체라는 것이다.
간단한 코드를 보자.

export default function SomeCom() {
  const ageRef = useRef<number>(0)

  const click4Event = () => {
    ageRef.current += 1
    console.log("ageRef.current = ", ageRef.current)
  }

  return (
    <>
      <button onClick={click4Event}>한살 Plus~</button>
    </>
  )
}

위 코드를 실행하면 콘솔에 ageRef.current가 +1하는 모습을 볼 수 있을 것이다.
그리고 랜더링이 일어나지 않는 부분도 확인 가능할 것이다.

위에서 선언된 세 가지 중 1번 항목이 여기와 같다.

function useRef(initialValue: T): MutableRefObject //1

근데 여기서 무지성으로 ageRef에 숫자 0대신 null을 넣어보자.
에러가 날 것이다.

왜 에러가 나냐 하면 선언된 형태 중 1번이 아닌 2번을 사용하기 때문이다. 이유는 아래로 내려가자


RefObject

설명에 앞서 아래의 선언을 보자.

function useRef(initialValue: T | null): RefObject //2

잘 보면 전달인자에 제너릭으로 된 초기화 외에 또 올 수 있는 값은 null이라고 명시되어 있다.
이를 보면 위 MutableRefObject예제에서 null을 주입했다면 RefObject를 반환하는 선언으로 변경된 것을 확인할 수 있다.

RefObject 타입은 DOM 유형을 담을 때 사용한다.
근데 읽기 전용인거 같은데, input 같은거를 ref로 가져와서 수정해보면 또 된다.

이거는 current 하위 속성의 value는 프로퍼티 플래그가 얇은 복사(Shallow)를 하기 때문이다.
그래서 current 프로퍼티 자체를 수정하려 하면 에러가 나지만, current는 에러가 나지 않는다.


기타 사항 및 알아둘 점

useRef는 항상 didMount가 되어 DOM에 반영이 된 후에 사용하자.
당연한 이야기겠지만 DOM을 참조해야 하는데 DOM이 mount 되기 전이면 당연 값은 null이나 undefined 일 것이다.
그래서 useEffect에서 사용하는 것이 좋다.

그리고 조건 랜더링이나 컴포넌트가 unmount 되는 상황이 올 수 있기에 항상 체크를 하고 사용하는 것이 좋다.
if문 등으로 textInputRef.current 를 검사하고 사용하면 좋다.

참조

React 공식 참조 문서(useRef)