useRef(typescript)

김정민·2022년 5월 5일
2
post-thumbnail

typescript에서 useRef를 쓰면 주의해야할 점이 몇 가지 존재한다.

useRef가 다른 hook들에 비해서 사용빈도가 낮지만, 확실히 알아보고자 한다.

1. useRef

자바스크립트에서 특정 DOM(태그)을 선택할 때 getElementById, querySelector 같은 DOM Selector 함수를 사용한다.

하지만 React에서 특정 DOM을 선택해야할 땐 이 기능을 대체할 수 있는 useRef 훅을 제공한다.
(class 컴포넌트에서 사용했던 React.createRef와 마찬가지로 DOM 노드를 저장하는 데 사용)

useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지됩니다.

초기값으로 null을 넣어주는 이유는, 명시적으로 빈 레퍼런스를 생성했음을 알려주기 위함입니다.

function Sample() {

  const inputSpace = useRef();
  const onFocus = () => {
    inputSpace.current.focus();
  };

  return (
        <div>
          <input
            name="here"
            placeholder="여기에 focus 되도록"
            onChange={onChange}
            value={value}
            ref={inputSpace}
          />
          <button onClick={onFocus}>포커스</button>
        </div>
  );

}

사용하는 곳

위 코드처럼 focus를 선택해주거나 두 개 컴포넌트의 싱크를 맞출 때 (pagination 등) 필요하다.

2. useRef에 또 다른 기능

useRef Hook은 컴포넌트 안에서 어떤 변수를 관리할 수 있는 다른 기능이 있다.

변수 관리는 useState 사용하면 될 거라고 생각하는데, useRef으로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않는 것이 특징이 있어서 상황에 따라 선택해 사용하면 된다.


상태는 상태를 바꾸는 함수를 호출한 이후에, 렌더링 이후로 업데이트 된 상태를 조회할 수 있는데, useRef Hook으로 관리하고 있는 변수는 설정 후 바로 조회할 수 있다.

또한, useRef Hook으로 만들어진 변수는 React의 전역 저장소에 저장되기 때문에 함수를 다시 호출하더라도 마지막으로 업데이트한 current 값이 유지되는 장점이 있다.

이 기능이 유용하게 쓰이는 경우!

  • setTimeout, setInterval 을 통해서 만들어진 id
  • 외부 라이브러리를 사용하여 생성된 인스턴스
  • scroll 위치

2.1 속성 값을 초기화(clear)할 필요가 있는 경우.

// App.js

const RSPfunction = () => {
  const [result, setResult] = useState('');
  const [imgCoord, setImgCoord] = useState(rspCoords.바위);
  const [score, setScore] = useState(0);
  const interval = useRef();

  useEffect(() => { 
    interval.current = setInterval(changeHand, 100);
    return () => {
      clearInterval(interval.current);
    }
  }, [imgCoord]); 


//  코드 생략
  • 예를 들어, 카운터의 값을 0으로 초기화 할 필요가 있을 때. (타이머 0으로 만들기 같은...)
  • setInterval 이나 setTimeout과 같은 함수는 clear 시켜주지 않으면 메모리를 많이 소모하기 때문이다.

2.2 useRef 변수관리

const nextId = useRef(4);
const onCreate = () => {
  dispatch({
    type: 'CREATE_USER',
    user: {
      id: nextId.current,
      username,
      email
    }
  });
  nextId.current += 1;
};

nextId라는 값을 수정할 때에도 .current 값을 수정하면 되고, 조회할 때에도 .current 값을 조회하면 된다

3. useRef (typescript)

useRef의 반환 타입은 MutableRefObject와 RefObject가 존재한다.

interface MutableRefObject<T> {
    current: T;
}

interface RefObject<T> {
    readonly current: T | null;
}

RefObject 타입은 readonly라는 것을 확인할 수 있다.

또한 타입스크립트에서 useRef에 대해 3가지 로 타입선언을 해둠 (overloading 이라고 함)

@types/react의 index.d.ts를 보면 useRef 훅은 3개의 정의가 오버로딩되어있는 것을 확인할 수 있다

3가지 타입

1. 매개 변수가 제네릭과 일치하는 useRef (MutableRefObject)

function useRef<T>(initialValue: T): MutableRefObject<T>;

2. 초기값에 null이 될 수 있는 유니언 타입을 지정하면 (RefObject)

인자의 타입이 null을 허용하는 경우, RefObject<T>를 반환한다

function useRef<T>(initialValue: T|null): RefObject<T>;

3. 제네릭에 undefined를 넣는 경우입니다. (MutableRefObject)

function useRef<T = undefined>(): MutableRefObject<T | undefined>;

추가


이런식으로 타입을 지정하지 않게되면

제네릭타입은 매개변수에 type을 가지고 정해지는 것 같다


왠만하면 타입을 지정해주도록 하자

0개의 댓글