TypeScript에서 Function Components와 React.FC
: 균형 잡힌 토론
React와 TypeScript가 함께 프로젝트에 참여했습니다. TypeScript가 말하길, "내가 타입 관리를 할게." React는, "내가 렌더링을 담당할게." 그 사이 누군가가 질문합니다:
React.FC
를 써야 할까요, 아니면 함수에 바로 타입을 지정하는 게 나을까요?
합리적인 질문입니다. 언뜻 보면 React.FC
는 다듬어지고 공식적이며, 세련되어 보이죠. 마치 코드에 와인 한 잔을 따라주며 "컴포넌트를 우아하게 만들어 보자"고 말하는 듯합니다. 하지만 속을 들여다보면, 현대 TypeScript가 거의 벗어나 온 짐짝 같은 면도 함께 가지고 있습니다.
좀 더 자세히 살펴봅시다.
두 가지 스타일
기본 함수 컴포넌트
type Props = { title: string };
function MyComponent({ title }: Props) {
return <h1>{title}</h1>;
}
깔끔하고 명확하며 이해하기 쉽습니다. 블랙 커피처럼, 군더더기 없이 일을 해냅니다.
또는 화살표 함수 방식이 더 마음에 든다면:
const MyComponent = ({ title }: Props) => {
return <h1>{title}</h1>;
};
둘 다 유효하고 가독성이 좋으며 현재 베스트 프랙티스와 잘 부합합니다.
React.FC 변형
import { FC } from 'react';
type Props = { title: string };
const MyComponent: FC<Props> = ({ title }) => {
return <h1>{title}</h1>;
};
이 버전은 컴포넌트를 제네릭 타입으로 감쌉니다. 더 "공식적"으로 보이고, 최근 TypeScript 유틸리티 타입을 접했다면 자연스러운 느낌—비밀 클럽에 들어온 것 같은 느낌이 들 수도 있죠. 하지만 가끔은 비밀 클럽에도 주의 사항이 있습니다.
React.FC가 실제로 하는 일
React.FC(React.FunctionComponent의 줄임말)는 함수 컴포넌트를 설명하는 헬퍼 타입입니다. 몇 가지 기본 동작을 제공합니다:
- 기본적으로 children prop을 포함합니다(필요 여부와 상관없이).
- 특정 에디터에서 자동 완성 기능을 약간 향상시킬 수 있습니다.
- 반환 타입을 좀 더 명시적으로 만들어 줄 수 있지만, 실제로는 거의 중요하지 않습니다.
이들은 작은 편의 기능이며, React + TypeScript 초창기에는 더 유용했습니다. 하지만 시간이 흐르면서 이런 "기능"들은 오히려 방해가 되는 경우가 많아졌습니다.
왜 인기가 시들해지고 있을까?
React.FC는 TypeScript에서 주머니가 많지만 대부분 사용하지 않는 카고 팬츠 같다고 할 수 있습니다.
- 암묵적 children 포함
모든 컴포넌트가 children prop을 받는데, 그 컴포넌트가 원하지 않아도 포함됩니다. 타입에 children이 있다고 가정해 버리면 개발자가 혼란스러운 버그를 만날 수 있습니다. (경고: 실제로 children이 없을 수도 있습니다.)
- 제네릭과 어울리지 않음
컴포넌트가 제네릭을 필요로 할 때, React.FC는 오히려 문법을 복잡하게 만들며, TypeScript가 덜 도움이 되게 만듭니다.
- 장황하지만 명확하지 않음
const MyComponent: FC<Props>
라고 쓰는 것은 props를 직접 타입 지정하는 것보다 길고, 경우에 따라 이해하기 더 어렵습니다.
- 더 이상 필요하지 않음
React.FC를 쓰던 초기 이유들—에디터 지원, JSX 타입 추론 등—은 대부분 TypeScript의 발전으로 해결되었습니다. 그때는 현실적인 해결책이었지만, 지금은 구식 스타일일 뿐입니다.
비교 대조
특징 | function Component() | const Component: FC |
---|---|---|
children 포함? | 선언한 경우에만 포함 | 항상 포함 |
제네릭 지원? | 자연스럽게 지원 | 추가 노력이 필요 |
장황한가? | 최소한 | 확연히 더 장황함 |
에디터 지원? | 충분함 | 특정 경우에 약간 더 좋음 |
권장되는가? | 예 | 더 이상 아님 |
권장되는 접근법
커뮤니티의 합의는 간단합니다: props를 직접 타입 지정하세요. 컴포넌트가 children을 받길 원하면 명시하세요. 그렇지 않으면 받지 않습니다. 이런 정직함이 미래의 당신에게 고마움으로 돌아옵니다.
type Props = {
title: string;
children?: React.ReactNode;
};
const MyComponent = ({ title, children }: Props) => (
<div>
<h1>{title}</h1>
{children}
</div>
);
명시적이고 유지보수에 용이하며, 컴포넌트가 children을 처리하지 않을 때까지 처리하는 척 하지 않습니다.
React.FC가 여전히 유용한 상황이 있을까?
가끔은 있습니다. 레거시 코드베이스에서 React.FC에 많이 의존하는 경우, 일관성을 유지하는 게 코드를 모두 다시 작성하는 것보다 더 중요할 수 있습니다. 빠르게 컴포넌트를 만들어야 하고 children 타입에 신경 쓰기 싫을 때, FC는 시간을 절약할 수도 있습니다.
하지만 일반적으로 그것들은 규칙을 증명해 주는 예외일 뿐입니다.
마무리하며
React.FC가 틀린 것은 아닙니다. 단지 더 이상 필수적이지 않을 뿐입니다. 현대 TypeScript는 React 컴포넌트 타입 지정을 더 간단하고 예측 가능하게 만들어주었습니다.
다음에 FC를 쓸 때는 잠시 멈춰서 그것이 진짜로 가치를 더하는지, 아니면 단지 불필요한 층만 늘리는지 생각해보세요. 대부분의 경우, 단순한 타입 지정 함수가 더 나은 선택일 것입니다.
소프트웨어도, 인생도 명확함이 영리함을 이깁니다. 그리고 놀라움이 적다는 것은 후회도 적다는 뜻이니까요.