리액트 기반 프로젝트에서 컴포넌트를 일반함수/화살표함수로 선언한것을 혼용한것을 봤어도,
클래스 컴포넌트와 함수 컴포넌트를 혼용하는 것은 본적이 없었다.
평소에는 화살표함수로 컴포넌트를 작성하되, 재사용/선언형 코드/상태로직 분리의 목적으로 커스텀훅을 주로 사용했었다.
그럼 클래스 컴포넌트를 만났을때, 커스텀훅을 클래스 컴포넌트에 적용해야한다면 어떻게 해야할까?
(클래스 컴포넌트를 함수로 바꾸세요 ㄹㅇㅋㅋ도 가능하겠지만, 입장을 바꿔서 클래스 컴포넌트인 거대한 프로젝트에 새로운 기능을 함수 컴포넌트 + 커스텀 훅 패러다임으로 구현한다고 하고, 그 기한이 짧은 경우로 생각해보자.)
아래는 Toast 컴포넌트를 전역에다가 선언해주는 Provider이고 그 아래는 hook이다.
const useToast = () => {
const { title, text, theme, isVisible } = useSelector(state => state.toastReducer);
const dispatch = useDispatch<AppDispatch>();
useEffect(() => {
if (!isVisible) return;
let timeId = setTimeout(() => {
dispatch(setHideToast());
}, TOAST_TIMER);
return () => {
clearTimeout(timeId);
};
}, [isVisible]);
return {
title,
text,
theme,
isVisible,
};
};
export default useToast;
export type Props = ReturnType<typeof useToast>;
class ToastProvider extends React.Component<React.PropsWithChildren<Props>> {
render() {
const { children, title, text, theme, isVisible } = this.props;
return (
<>
<ToastBase title={title} text={text} theme={theme} isVisible={isVisible} />
{children}
</>
);
}
}
클래스 컴포넌트에 useToast를 적용시킬 수 있을까?
위에서 이미 구현되어있지만, 일단 클래스 컴포넌트의 인자들을 useToast의 반환값에서 필요한 녀석들로 넘겨받는다.
(여기서는 모든 인자 넘겨받아서 ReturnType<typeof useToast>로 했다 ㅇ.ㅇ)
그리고 Wrapper로 클래스 컴포넌트를 감싸주면된다.
const withHasMounted = (Comp: React.ComponentClass<React.PropsWithChildren<Props>>) => {
return ({ ...props }) => {
return <Comp {...useToast()} {...props} />;
};
};
export default withHasMounted(ToastProvider);
이제 ToastProvider라는 클래스 컴포넌트에서, useToast라는 커스텀훅을 사용할 수 있다.
원리를 살펴보면, withHasMounted라는 함수의 반환값은 일반적인 화살표함수로 구현된 함수 컴포넌트이다.
(Hoc)
그리고 이 Hoc에서는 커스텀훅을 사용하고, 커스텀훅의 반환결과를 클래스 컴포넌트에 넘겨준다.
그럼, 클래스 컴포넌트는 인자들을 prop으로 받아서 렌더링을 수행하는 원리이다.
지금 까지 방법을 알아보았다.
하지만 머니머니해도 하나로 통일하는게 제일 편할거같다.