useRef를 하나의 컴포넌트에서만 사용하는게 아니라 props로 넘겨줘서 사용할 때가 있다.
예를들어, 메뉴바와 페이지 컴포넌트를 따로 만들어서 사용할 때가 있겠다.
메뉴를 눌러 페이지의 특정 위치로 이동하고 싶을 때 ref를 사용한다고 하자.
이 때, 메뉴바 컴포넌트에 ref를 줘야지 어떤 메뉴가 어디로 이동할지 알텐데...
다른 컴포넌트에 props로 전달할 때 어떻게 타입을 정의해야할까?
찾아본 결과, Arrow Function 사용법이 압도적으로 많았다.
필자는 컴포넌트를 만들 때 Regular Function을 많이 쓰기 때문에,
두 함수 모두 기록하려고 한다.
//* ArtistPage.tsx *//
import ArtistsList from "./ArtistsList";
function ArtistPage() {
const artistRef = useRef<HTMLDivElement>(null);
// ... //
return (
<Layout>
<ArtistsList ref={artistRef} moveToArtist={moveToArtist} />
</Layout>
);
}
export default ArtistPage;
ref를 받아가는 컴포넌트에서 속성을 ref로 작성해야지만 된다.
필자는 이걸 모르고
// 틀린 방법
<ArtistsList artistRef={artistRef} moveToArtist={moveToArtist} />
이렇게 작성했다가, 1시간을 헤맸다.
// 맞는 방법
<ArtistsList ref={artistRef} moveToArtist={moveToArtist} />
꼭 ref를 사용하자.
//* ArtistsList.tsx *//
import React from "react";
import ArtistsList from "./ArtistsList";
interface PropsType {
moveToArtist: (index: number) => void;
}
const ArtistsList = React.forwardRef<HTMLDivElement, PropsType>(
({ moveToArtist }, artistRef) => {
return (
<nav className="hidden lg:block top-1/2 left-1/2 sticky">
<ul className="flex flex-col items-center font-semibold xl:text-xl">
{artistArr.map((item, index) => (
<li
className="hover:cursor-pointer"
key={index}
onClick={() => moveToArtist(index)}
>
{item.name}
</li>
))}
</ul>
</nav>
);
}
);
export default ArtistsList;
Arrow Function에서는 React.forwardRef를 사용한다.
위 코드는 필자의 코드에 적용한 것이라서 헷갈릴 수 있으니, 간단한 예시를 아래 작성해보겠다.
import React from "react";
const name = React.forwardRef<RefType ,PropsType>((props, ref) => {
// ... //
})
PropsType은 interface나 type을 사용해서 선언한 것을 가져오면 되고, RefType은 부모 컴포넌트에서 작성한 ref의 타입을 써주면 된다.
잘 보면, 제네릭 타입 부분은 ref, props 순서인데, 파라미터 부분은 props, ref 순서이다.
forwardRef 자체가 저런 식으로 작성해야하는 것이므로, 이상하더라도 그렇구나하고 받아들이자.
//* ArtistPage.tsx *//
import ArtistsList from "./ArtistsList";
function ArtistPage() {
const artistRef = useRef<HTMLDivElement>(null);
// ... //
return (
<Layout>
<ArtistsList artistRef={artistRef} moveToArtist={moveToArtist} />
</Layout>
);
}
export default ArtistPage;
//* ArtistsList.tsx *//
interface ArtistsListPropsType {
artistRef: React.ForwardedRef<HTMLDivElement>;
}
function ArtistsList({ artistRef }: ArtistsListPropsType) {
return (
// ... //
);
}
export default ArtistsList;
Regular Function에서는 흔히들 Typescript에서 props에 타입을 알려주는 방법과 동일하다.
interface의 artistRef의 타입을 살펴보자.
div에 대한 ref기 때문에 HTMLDivElement를 사용했다는 점에 주의!
React.ForwardedRef<HTMLDivElement>;
위와 같은 방식으로 타입을 정의해주면 된다.
위에서 이미 설명했지만 Arrow Function일 때와, Regular Function일 때 눈치 못 채고 실수할 수 있는 부분이 있다.
부모 컴포넌트에서 자식 컴포넌트로 ref값을 넘겨 줄 때 아래와 같이 작성해줘야한다.
// Arrow Function
<ArtistsList ref={artistRef} moveToArtist={moveToArtist} />
// Regular Function
<ArtistsList artistRef={artistRef} moveToArtist={moveToArtist} />
전자는 ref라는 속성을 반드시 기입해줘야하고, 후자는 그럴 필요가 없다.