React.FC vs JSX.Element

deli-ght·2021년 12월 28일
13

Typescript

목록 보기
1/2
post-thumbnail

타입스크립트 공식 홈페이지 참고하기

JSX.element

값-기반 요소 (value-based elements)

사용자가 만든 사용자 정의 컴포넌트로 스코프 내의 식별자에 의해 사용됨

Element를 선언하는 방법은 두가지가 있음.
1. Function Component (FC)
2. Class Component

타스에서는 함수형 컴포넌트로 표현을 해석을 기본으로 하고, 함수형 컴포넌트가 확인되지 않으면 클래스 컴포넌트로 해석함. 기본적으로 JSX의 결과 타입은 any이지만, JSX.element 인터페이스를 통해 해당 타입으로 변경 가능

클래스형 컴포넌트에서 render메소드를 통해 ReactNode를 리턴하는 반면, 함수형 컴포넌트ReactElement를 리턴. ReactElement는 React.createElement로 컴파일 되며, JSX.Elementany타입의 propstype을 가진 React.createElement이다.

  • TS class component: returns ReactNode with render(), more permissive than React/JS
  • TS function component: returns JSX.Element | null, more restrictive than React/JS

역사적인 이유와 하위호환성 문제로 두 컴포넌트의 리턴 타입이 다름.
따라서 함수형 컴포넌트를 사용한다면 리턴값의 기본 타입으로 JSX.element를 사용해주어야함.

React.FC

FC는 Function Component의 약자로 그대로 넣어서 사용해도 돌아감
React.FC 사용시, Props의 타입을 Generic에 넣어서 사용
React.FC <string>

본 컴포넌트는 단순한 함수가 아니라 함수형 컴포넌트임을 명시해주는 역할로 화살표 함수를 사용해 컴포넌트를 정의할 때, 컴포넌트 타입을 정하기 위해 사용되기도 함.

const App : React.FC = () => {}

-> class component로 만든 경우, React.ClassComponent사용 가능

타입값이 JSX를 리턴하는 함수이므로 리턴값이 없다면 오류가 발생함

props에 기본적으로 children이 들어있음.

하지만 children이 옵션으로 들어가 있어, 컴포넌트 props의 타입이 정할 수 없는 단점이 있음.
children의 요소로 어떤 타입이 들어올 지 모르기 때문

defaultProps, propTypes, contextTypes 자동완성.

const로 선언되는 컴포넌트를 변수로 생각하지 못하도록 React.FC로 타입을 지정해줌.
그래서 선언된 컴포넌트의 내장함수로 리액트 함수형 컴포넌트의 내장함수들을 사용할 수 있음.

그러나 아직 defaultprops를 아직 인식하지 못하는 성능상의 문제가 존재함.

Defaultprops에 대한 논쟁
defaultProps vs object default values
사람들이 선호하는 방식은 object default values
why ? 기존의 방식이 너무 복잡하고 FC로 defaultProps를 적용하기 위해선 별도의 처리가 필요함.

defaultProps 적용방법

import * as React from "react";

type ComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P>
  ? JSX.LibraryManagedAttributes<T, P>
  : never;

interface IProps {
  name: string;
}
const defaultProps = {
  age: 25,
};
const GreetComponent = ({ name, age }: IProps & typeof defaultProps) => (
  <div>{`Hello, my name is ${name}, ${age}`}</div>
);
GreetComponent.defaultProps = defaultProps;

// later

const TestComponent = (props: ComponentProps<typeof GreetComponent>) => {
  return <h1 />
};

// No error
const el = <TestComponent name="foo" />;

그래서 defaultProps를 사용하는 대신, object default value를 주는 것을 추천

type GreetProps = { age?: number };
const Greet = ({ age = 21 }: GreetProps) => // etc

결론

// Use type inference; inferred return type is `JSX.Element | null`
const MyComp1 = ({ condition }: { condition: boolean }) =>
    condition ? <div>Hello</div> : null

// Use explicit function return types; Add `null`, if needed
const MyComp2 = (): JSX.Element => <div>Hello</div>; 
const MyComp3 = (): React.ReactElement => <div>Hello</div>;  
// Option 3 is equivalent to 2 + we don't need to use a global (JSX namespace)

// Use built-in `FunctionComponent` or `FC` type
const MyComp4: React.FC<MyProps> = () => <div>Hello</div>;

컴포넌트의 리턴값을 설정한다. : JSX.Element
변수에게 타입을 설정한다. : React.FC<type>

Create react app에서는 React.FC 사용이 어려울 수 있음
https://stackoverflow.com/questions/58123398/when-to-use-jsx-element-vs-reactnode-vs-reactelement/59840095#59840095

profile
PRE-FE에서 PRO-FE로🚀🪐!

3개의 댓글

comment-user-thumbnail
2021년 12월 30일

최고에요!

2개의 답글