이번에는 ref에 타입스크립트를 적용하는 방법을 알아보자.
다음 컴포넌트를 한번 보자. input 요소에 ref가 참조가 걸려있다.
const UserSearch: React.FC = () => {
const inputRef = useRef();
const [name, setName] = useState("");
const [user, setUser] = useState<{ name: string; age: number } | undefined>();
const onClick = () => {
const foundUser = users.find((user) => {
return user.name === name;
});
setUser(foundUser);
};
return (
<div>
User Search
<input
ref={inputRef}
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button onClick={onClick}>Find User</button>
<div>
{user && user.name}
{user && user.age}
</div>
</div>
);
};
여기서 input 속성인 ref
에서 발생하는 오류를 한번 보자.
마우스 오버를 하면 오류가 보이는데 그냥 봐서는 이해가 잘 되지 않는다. ref를 만들 때 HTML 요소를 참조하고 그 사이에 <>으로 ref가 참조하는 타입을 정의를 한다. 여기서는 <HTMLInputElement>
를 추가한다.
const inputRef = useRef<HTMLInputElement>();
HTML 요소는 다른 인터페이스이다. HTMLInputElement를 클릭해서 세부 내용을 한번 보자.
...
interface HTMLHeadElement extends HTMLElement {}
interface HTMLHRElement extends HTMLElement {}
interface HTMLHtmlElement extends HTMLElement {}
interface HTMLIFrameElement extends HTMLElement {}
interface HTMLImageElement extends HTMLElement {}
interface HTMLInputElement extends HTMLElement {}
...
interface HTMLDivElement extends HTMLElement {}
...
여기서 HTMLElement에 대한 모든 요소의 인터페이스가 정리되어 있다. HTMLInputElement을 추가했는데도 ref에 오류는 그대로 표시가 된다. ref에 수정해야 할 것이 아직 남아 있다는 뜻이다.
우선, 화면에 컴포넌트를 렌더링할 때, ref를 정의하지만 어느 엘리먼트에 참조해야 할지는 모른다. 즉, 타입스크립트 입장에서는 알 수가 없다는 뜻이다.
즉, 소스코드에서 input
에서 ref={inputRef}
속성을 삭제를 하면 inputRef는 참조를 해야 할 대상이 없어진다. 타입스크립트는 ref가 어떤 HTML 엘리먼트에 참조를 하지 못할 수도 있다는 것을 알고 있다. 그래서 useRef를 생성할 때 null
이 될 수 있다고 타입스크립트는 판단한다. 그래서 useRef에서는 아래와 같이 null을 추가해야 한다. 그리고 기본값도 null로 설정해야 한다.
const inputRef = useRef<HTMLInputElement | null>(null);
여기서 컴포넌트가 최초 로딩되었을 때 input에 focus를 설정해보자. 아래와 같이 useEffect를 사용하면 된다.
useEffect(() => {
inputRef.current?.focus();
}, []);
inputRef.current는 null이 될 수 있기 때문에 inputRef.current?
로 사용하였다.
이런식으로 ref에는 ref가 참조하는 HTMLElement의 타입을 추가하면 되고 null이 될 수 있다는 것을 생각해야 한다.
참고
https://www.udemy.com/course/react-and-typescript-build-a-portfolio-project