React + Typescript 에서 FC 를 사용하면 안되는 이유

2023-06-02-react-fc.md

Posted by 전봉근 on Friday, June 2, 2023 Tags: javascript react   2 minute read

React + Typescript 에서 FC 를 사용하면 안되는 이유

먼저 React17 이하에서는 아래와 같이 React.FC 사용이 가능하며 React18 이상부터는 없어졌다고 한다.
참고

그러나 FC 를 사용하는건 좋은 방법이 아니며 CRA 에서는 여러가지의 이유로 FC 를 없애야 한다고 이슈가 올라왔었고 반영되었으며 이유는 아래 설명을 참고하자.

  1. children 을 암시적으로 가지고 있다.
    • FC 를 이용한 컴포넌트 props 는 type 이 ReactNode 인 Children 을 암묵적으로 가지게 되며 이는 꼭 타입스크립트에 한정하지 않더라도 안티패턴이라고 한다. 왜냐하면 children 이라는 암묵적이었던 키워드는 자식노드가 필요한지 아닌지의 의도를 명확하게 드러낼 수 없다는, 타입의 관점에서는 꽤 크리티컬한 문제를 갖고 있었다. (타입에 자식 노드가 꼭 필요한 컴포넌트에 자식 노드를 넣지 않았을 경우 혹은 그 반대의 경우를 타입으로 잡아내지 못한다는 단점이 존재 즉, 암묵적으로 선언됐던 children 을 명시적으로 컴포넌트에 맞게 선언을 하자는 취지라고 한다.)
    • 예시
      • AS-IS (react 를 업데이트하면 하기 주석의 에러가 표시)
        const Example: React.FC = ({ children }) => <div>{children}</div>;
        // "TS2339: Property 'children' does not exist on type '{}'."       
        
      • TO-BE (자식 컴포넌트가 꼭 필요하다는 의도를 타입으로 정의)
        type Props = {
          children: React.ReactNode;
          // children?: React.ReactNode; 자식노드가 옵셔널한경우
        };
        
        const Example: React.FC<Props> = ({ children }) => <div>{children}</div>;       
        
  2. 제네릭을 지원하지 않는다.
    • 하기 제네릭 컴포넌트를 작성한 내용을 보자
      // 제네릭 컴포넌트 작성
      type GenericComponentProps<T> = {
        prop: T;
        callback: (t: T) => void;
      };
      
      const GenericComponent = <T>(props: GenericComponentProps<T>) => {
        /*...*/
      };     
      
      // 허용 X (T 를 넘겨줄 방법이 없기 때문에 FC 에서 허용되지 않는다)
      const GenericComponent: React.FC</* ??? */> = <T>(props: GenericComponentProps<T>) => {/*...*/}
      
  3. 네임스페이스 패턴을 이용할 때 불편하다.
    • 하기 코드와 같이 연관성 있는 컴포넌트에 대해 네임스페이스 패턴을 적용하는 것은 매우 많이 쓰이는 방법이다.
      <Select>
        <Select.Item />
      </Select>
      
    • FC 를 사용하고도 상기 패턴을 적용할 수 있지만 많이 불편해진다.
      // FC를 사용할 때
      const Select: React.FC<SelectProps> & { Item: React.FC<ItemProps> } = (
      props
      ) => {
        /* ... */
      };
      Select.Item = (props) => {
        /*...*/
      };     
      
      // FC를 사용하지 않을 때
      const Select = (props: SelectProps) => {
        /* ... */
      };
      Select.Item = (props: ItemProps) => {
        /*...*/
      };     
      
  4. FC 를 사용하면 코드가 더 길어진다.
    const C1: React.FC<CProps> = (props) => {};  // FC 사용 O
    const C2 = (props: CProps) => {};    // FC 사용 X
    

참고

  • https://emewjin.github.io/
  • https://blog.shiren.dev/