프로젝트 중, 커스텀 훅 내부에서 인자로 받아온 ref를 다시 return하는 다른 컴포넌트에 props로 전달해 줄 일이 있었다.
const renderCategorySelect = (isSub: boolean) => {
return (
<CustomSelect
{...{
...SelectProps,
onChange: handleCategoryChange,
ref: isSub ? subRef : null,
options: isSub
? copyOptionGroup.CategoryOptions[0].subCategory
: copyOptionGroup.CategoryOptions,
}}
/>
);
};
해당 코드는 커스텀 훅 내부에 정의된 함수로, 지정한 커스텀 select 컴포넌트를 반환하는 데 이 때 내부 로직처리에 따라 정의된 기본 옵션들 또한 props 객체 형식으로 전달해 주고 있었다.
문제는 여기서 ref 값도 할당해 주는 부분에서 에러가 발생했다.
내용을 해석해 보자면 함수형 컴포넌트에서는 ref 라는 이름으로 props 속성같은 것을 전달할 수 없는 듯하다.
클래스형과 달리 함수형에서는 인스턴스를 생성할 수 없기에 ref를 속성으로 사용할 수 없음!
좀 더 찾아보니 ref는 DOM 참조를 위해 react 에서 내부적으로 사용되며, 이는 예약어이기 때문에 props로 전달할 때 ref
라는 이름값을 사용할 수 없다는 것이다.
(속성으로 부여되는 key
같은 것과 비슷한 맥락)
이에 대한 해결방안으로 에러에서 제안한 것처럼 forwardRef 를 사용해보기로 했다.
공식문서에 따르면 해당 ref를 전달받을 해당 컴포넌트를 forwardRef로 감쌎게 되면, 이 때 감싸진 컴포넌트 함수의 두번째 인자로 ref 객체를 전달받을 수 있다고 한다
const renderCategorySelect = (isSub: boolean) => {
return (
<CustomSelect
{...{
...SelectProps,
onChange: handleCategoryChange,
ref: isSub ? subRef : null,
options: isSub
? copyOptionGroup.CategoryOptions[0].subCategory
: copyOptionGroup.CategoryOptions,
}}
/>
앞서 코드와 똑같이 우선은 ref 속성을 전달해준다.
function CustomSelect(props, ref) {
useImperativeHandle(ref, () => {
customFocus: () => ref.current.focus();
});
return (
<>
<S.CustomSelector {...props} />
</>
);
}
export default forwardRef(CustomSelect);
ref를 전달 받는 컴포넌트 자체를 forwardRef로 감싸준다. 감싸준 이후부터는 이 컴포넌트 함수의 두번째 인자로 ref 객체를 그대로 전달받아 사용가능하다.
추가로 useImperativeHandle
라는 react에서 자체 제공하는 함수를 이용해 ref 내부의 메서드를 사용자 정의(Customizing) 해줄 수도 있다.