[React, TS] React.FC 사용을 추천하지 않는 이유

chaevivi·2023년 12월 15일
0
post-thumbnail

React Function Components

React.FC는 React + TypeScript에서 자주 사용되는 함수형 컴포넌트 선언 방법 중 하나입니다. 하지만 React.FC 사용에 대해 개발자들 사이에서 자주 논란이 발생하고 있고, 'React.FC 사용을 자제하자'로 결론이 모아지고 있다고 합니다.
이번 포스트에서는 어떤 부분 때문에 그러한 결론이 나왔는지 자세히 알아보고자 합니다.



1. React + TS에서 함수형 컴포넌트 선언 방법

React와 TypeScript를 사용하는 환경에서 함수형 컴포넌트를 선언하는 방법에는 여러 가지가 있습니다. 각각의 차이점에 대해 알아봅시다.


먼저, prop의 타입을 선언합니다.

type AppProps = {
	message: string;
}

✅ 타입을 확장할 수 있도록 내보낼 때는(export) interface를 사용하세요. interface와 type의 차이점을 알고 싶다면 여기를 클릭하세요.


const App = ({ message }: AppProps) => <div>{message}</div>;
  • 함수형 컴포넌트를 선언하는 가장 쉬운 방법입니다.
  • 이때는 반환 타입이 추론됩니다.

const App = ({ message }: AppProps): React.JSX.Element => <div>{message}</div>;
  • 실수로 다른 타입을 반환하면 오류가 발생하도록 반환 타입을 작성할 수 있습니다.

const App = ({ message }: { message: string }) => <div>{message}</div>;
  • 타입 선언을 괄호 안에 작성할 수 있습니다.
  • prop 타입의 이름을 제거했지만 반복되는 부분이 있습니다.

const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);
  • 위의 방법들 외에 React.FunctionComponent(줄여서 React.FC)를 사용할 수 있습니다.
  • 최신 리액트 타입과 타입스크립트 5.1.에서는 대부분 코드 작성 스타일에 따라 선택할 수 있지만 그렇지 않으면 권장하지 않습니다.


2. React.FC가 권장되지 않는 이유는?

React 17이나 TypeScript 5.1 이하 버전을 사용하고 있다면 권장하지 않습니다.


2.1. 일반 함수와 React.FC의 다른 점

(1) React.FC는 리턴 타입을 명시하지만, 일반 함수는 타입을 암시합니다. (또는 추가로 타입을 지정해야 합니다.)

type FC<P = {}> = FunctionComponent<P>;

interface FunctionComponent<P = {}> {
  (props: P, context?: any): ReactNode;
  propTypes?: WeakValidationMap<P> | undefined;
  contextTypes?: ValidationMap<any> | undefined;
  defaultProps?: Partial<P> | undefined;
  displayName?: string | undefined;
}
  • node_modules/@types/react/index.d.ts 파일에서 React.FC가 가지고 있는 타입들을 살펴볼 수 있습니디.
  • 위에서 보이는 것처럼 React.FC는 타입을 명시하고 있습니다.
  • 반면 일반 함수에서는 리턴 타입을 명시적으로 작성해야 합니다.

(2) displayName, propTypes, defaultProps처럼 정적 프로퍼티들에 대해 타입 체크와 자동완성을 제공합니다.

  • React.FC는 정적 프로퍼티들에 대해 타입 체크와 자동완성을 지원합니다.
  • 하지만 React.FC에서 defaultProps의 사용에 대한 이슈가 끊이지 않고 있습니다.
    • React.FC에서 defaultProps는 선택 사항(optional)으로 설정되고 LibraryManagedAttributes 가 중단되어 코드가 원하는대로 작동하지 않습니다.
    • LibraryManagedAttributes는 컴포넌트의 props 타입에 대한 변환을 정의합니다.

(3) React 18 타입 업데이트 이전, React.FCchildren에 대해 암시적인 정의를 제공했는데(아래 참고), 이는 많은 논란이 있었고 이것이 Create React App TypeScript 탬플릿에서 React.FC가 제거된 이유 중 하나입니다.

// React 18 이전 
const Title: React.FunctionComponent<{ title: string }> => ({
  children,    // Error
  title,       // Error
}) => <div title={title}>{children}</div>;
  • 위의 코드를 React 18에서 작성하면 Binding element 'children'('title') implicitly has an 'any' type.ts(7031) 에러가 발생합니다.
  • 이 에러는 children(title)의 타입이 암시적으로 any 타입이 할당되어 발생한 에러입니다. props 객체가 매개변수에서 구조분해 되었기 때문입니다.
  • 따라서 React.FC를 에러없이 사용하려면 children에 직접 타입을 지정해주어야 합니다.
  • 하지만 React 18 이전에서는 에러가 발생하지 않습니다. 이는 컴파일 단계에서 에러를 해결할 수 있는 타입스크립트의 장점을 취할 수 없기 때문에 React와 TypeScript에서는 React.FC 사용을 권장하지 않습니다.



참고
🔗 Function Components: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components/
🔗 React.FC에 대한 issue: https://github.com/typescript-cheatsheets/react/issues/87
🔗 LibraryManagedAttributes: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html

profile
직접 만드는 게 좋은 프론트엔드 개발자

0개의 댓글