typescript에서 useRef를 쓰면 주의해야할 점이 몇 가지 존재한다.
useRef가 다른 hook들에 비해서 사용빈도가 낮지만, 확실히 알아보고자 한다.
자바스크립트에서 특정 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 등) 필요하다.
useRef Hook은 컴포넌트 안에서 어떤 변수를 관리할 수 있는 다른 기능이 있다.
변수 관리는 useState 사용하면 될 거라고 생각하는데, useRef으로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않는 것이 특징이 있어서 상황에 따라 선택해 사용하면 된다.
상태는 상태를 바꾸는 함수를 호출한 이후에, 렌더링 이후로 업데이트 된 상태를 조회할 수 있는데, useRef Hook으로 관리하고 있는 변수는 설정 후 바로 조회할 수 있다.
또한, useRef Hook으로 만들어진 변수는 React의 전역 저장소에 저장되기 때문에 함수를 다시 호출하더라도 마지막으로 업데이트한 current 값이 유지되는 장점이 있다.
이 기능이 유용하게 쓰이는 경우!
- setTimeout, setInterval 을 통해서 만들어진 id
- 외부 라이브러리를 사용하여 생성된 인스턴스
- scroll 위치
// 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]);
// 코드 생략
const nextId = useRef(4);
const onCreate = () => {
dispatch({
type: 'CREATE_USER',
user: {
id: nextId.current,
username,
email
}
});
nextId.current += 1;
};
nextId라는 값을 수정할 때에도 .current 값을 수정하면 되고, 조회할 때에도 .current 값을 조회하면 된다
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개의 정의가 오버로딩되어있는 것을 확인할 수 있다
function useRef<T>(initialValue: T): MutableRefObject<T>;
인자의 타입이 null을 허용하는 경우, RefObject<T>
를 반환한다
function useRef<T>(initialValue: T|null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
이런식으로 타입을 지정하지 않게되면
제네릭타입은 매개변수에 type을 가지고 정해지는 것 같다
왠만하면 타입을 지정해주도록 하자