tip) useRef가 중요한 것이 아니라 타이핑이 되어 있는 정의 부분으로 이동하여 살펴보는 것이 중요함을 강조하기 위함이고, useRef는 구체적인 실천의 예시일 뿐입니다.
일반 js를 사용할 때는 대두되지 않은 문제였지만, TS를 사용할 때 useRef에는 3가지 종류가 있습니다.
@types/react 에서 정의된 useRef의 d.ts를 살펴보면(굳이 찾을 필요 없이 useRef에 ctrl + click하면 됩니다.)
useRef에 3가지 종류가 있음을 확인할 수 있습니다. 정확히 말하자면 하나의 useRef인데 인자나 제네릭 타입에 따라 다른 것을 사용하도록 overload된 것입니다. (커서를 올려보면 +2 overloads가 있다고 확인할 수 있습니다)
useRef에 커서를 올려보면 다음과 같은 설명을 확인할 수 있습니다. 현재 사용중인 useRef는 MutableRefObject를 반환합니다. 가장 일반적인 형태라고 볼 수 있겠습니다.
1.
매개 변수가 제네릭과 일치하는 useRef입니다.
// TODO (TypeScript 3.0): <T extends unknown>
function useRef<T>(initialValue: T): MutableRefObject<T>;
// convenience overload for refs given as a ref prop as they typically start with a null value
/**
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
* (`initialValue`). The returned object will persist for the full lifetime of the component.
*
* Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
* value around similar to how you’d use instance fields in classes.
*
* Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type
* of the generic argument.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
그래서 구체적으로 MutableRefObject가 무엇인지 확인해봤더니 그냥 단순하게 <T> 제네릭으로 넘겨준 타입의 current 프로퍼티를 가진 객체였군요.
interface MutableRefObject<T> {
current: T;
}
2.
초기값에 null이 될 수 있는 유니언 타입을 지정하면 RefObject를 반환합니다.
// TODO (TypeScript 3.0): <T extends unknown>
function useRef<T>(initialValue: T|null): RefObject<T>;
// convenience overload for potentially undefined initialValue / call with 0 arguments
// has a default to stop it from defaulting to {} instead
/**
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
* (`initialValue`). The returned object will persist for the full lifetime of the component.
*
* Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
* value around similar to how you’d use instance fields in classes.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
RefObject가 무엇인이 찾아보니 MutableRefObject와 다르게 readonly 속성이기 때문에 값을 변화시킬 수 없습니다.
interface RefObject<T> {
readonly current: T | null;
}
2번과 같은 이러한 종류의 useRef면 current에 내용을 주입하는 용도로 useRef를 사용할 수 없습니다. current가 readonly 이기 때문입니다.
useRef는 보통 특정 DOM을 선택, 조작해야할 때 사용한다고 알려져 있지만, 꼭 그렇지만은 않습니다. useRef를 생성한 후 ref를 컴포넌트에 붙이지 않고 사용할 수도 있습니다. 값이 바뀌어도 화면이 리렌더링되지 않게 하기 위해서 사용하는 경우도 있습니다. (그리고 아시다시피 js에서는 함수도 값처럼 취급하므로 변수로 지정할 수 있습니다. )
이를 이용해서 다음과 같이 정의해보려고 했습니다. js에서는 아무 문제 없이 돌아가는 코드가.. TS에서는 작동하지 않습니다. 이러한 이유는 useRef의 3가지 종류 중 적절한 것을 사용하지 못했기 때문입니다.
const timeout = useRef(null); // RefObject 반환해서 current가 readonly가 됨
timeout.current = setTimeout(() => {
startTime.current = new Date().getTime(); // Error!
}, Math.floor(Math.random() * 1000) + 2000);
// const timeout = useRef<number | null>(null); // MutableRefObject을 사용하기 위함
// 이것으로 교체해줘야 오류가 안 남
3.
제네릭에 undefined를 넣는 경우입니다. MutableRefObject를 반환합니다.
제네릭이 undefined인 경우 사용되며, undefined이므로 매개 변수가 아예 없네요.
// TODO (TypeScript 3.0): <T extends unknown>
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
/**
* The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations.
* Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside
* `useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint.
*
* Prefer the standard `useEffect` when possible to avoid blocking visual updates.
*
* If you’re migrating code from a class component, `useLayoutEffect` fires in the same phase as
* `componentDidMount` and `componentDidUpdate`.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#uselayouteffect
*/
useRef를 쓰면서 무언가 에러가 나면 이 셋 중 어떤 useRef를 사용중인지를 체크해보면 됩니다.
* 간략하게 요약을하자면...
const menuRef = useRef<number>(0); // ref에 특정 값을 담는 용으로 사용할 때
const menuRef = useRef<HTMLInputElement>(null); // DOM을 다룰 때 반드시 초깃값은 null로 설정한다.
'React, Next, Redux > ⚛ React.TS' 카테고리의 다른 글
styled-components + typescript (0) | 2020.08.26 |
---|---|
React에서 Typescript 사용하기 (0) | 2020.03.18 |