리액트를 구현하는 방식은 크게 두 가지가 있다.
클래스 컴포넌트
, 함수 컴포넌트
이렇게 두 가지가 있는데,
타입스크립트를 사용하여 함수 컴포넌트 방식으로 구현할 때 사용하는 FC
라는 제네릭 타입이 존재한다.
React.FC의 FC는 함수 컴포넌트를 의미한다.
아래와 같이 코드를 작성할 수 있다.
import React from 'react';
import { ModalPagePropsType } from '../../model/props.model';
const AuthModal: React.FC<ModalPagePropsType> = ({ authModal, setIsOpenModal }) => {
return (
// (...생략)
)
}
나도 여태 위와 같이 FC를 사용하여 코드를 작성해왔는데, FC를 사용하는 방법에 단점이 있다는 것을 알게 되어 기록한다.
단점에는 어떤 것이 있을까?
말 그대로 children을 옵셔널하게 가지고 있다는 것이다.
export const Hello: React.FC<HelloProps> = ({ name }) => {
return <h1>Hello olleh! my name is {name}</h1>
}
const App = () => (
<>
<Hello name="suzi">
<span>{"I have children"}</span>
</Hello>
</>
)
위 코드를 보면 Hello 컴포넌트는 children을 렌더링하는 부분이 없음에도 불구하고 App 컴포넌트에서 오류 없이 정상적으로 작동한다.
이는 타입스크립트를 사용하면서 충분히 혼란을 줄 수 있는 여지가 있다.
컴포넌트에 children의 존재가 가능한지 여부를 확인하는 방법이 좋다.
만약 컴포넌트에 children이 존재할 수 도 있다는 것을 알려주기 위해서는
PropsWithChildren을 사용하는 것이 좋다. 아래와 같이 사용하면 된다.
function Card({ title, children }: PropsWithChildren<{ title: string }>) {
return (
<>
<h1>{title}</h1>
{children}
</>
)
}
React.FC 에서는 defaultProps
를 사용하지 못하게 한다.
defaultProps란 props의 default 값을 설정해주는 방법이다.
언어에서 전달 받는 매개변수의 default 값을 설정해주는 것과 비슷한 맥락이라고 생각하면 되겠다.
함수형 컴포넌트에서는 자바스크립트의 기본적인 기능을 활용하여 props의 기본값을 제공할 수 있었는데, 아래와 같이 사용하였다.
export const Hello: FC<HelloProps> = ({ name = "minsu" }) => {
return <h1>Hello olleh! my name is {name}</h1>
}
하지만 타입스크립트 3.1 버전 이후로 defaultProps
를 이해하는 메커니즘이 추가가 되었다고 한다. 하지만 React.FC는 defaultProps를 이해하지 못한다.
export const Hello: React.FC<HelloProps> = ({ name }) => {
return <h1>Hello olleh! my name is {name}</h1>
}
Hello.defaultProps = {
name:"minsu"
}
const App = () => (
<>
<Hello />
</>
)
위의 코드를 실행하면 name에 minsu가 들어오지 않는다.😂
해결 방법은 생각보다 간단하다.
아래와 같이 React.FC를 사용하지 않고 일반적인 함수 방식을 사용하면 된다.
export const Hello: = ({ name }: HelloProps) => {
return <h1>Hello olleh! my name is {name}</h1>
}
Hello.defaultProps = {
name:"minsu"
}
const App = () => (
<>
<Hello />
</>
)
위 코드를 실행하면 defaultProps가 제대로 동작하게 된다.
또한, 아래의 코드를 실행했을 때, children으로 인해 정상적으로 오류가 발생한다.
export const Hello = ({ name }: HelloProps) => {
return <h1>Hello olleh! my name is {name}</h1>
}
const App = () => (
<>
<Hello name="suzi">
<span>{"I have children"}</span> // Error
</Hello>
</>
)
React.FC
를 사용하는 것이 나쁜 것은 아니다. 이 글을 포스팅하기 위해 공부를 해보면서 위에서 React.FC의 단점이라고 언급했던 optional children을 React.FC의 장점이자 단점으로 생각하는 사람도 있었다. 상황에 따라 React.FC를 사용하는 것이 더 좋은 경우도 있을 수 있다는 것이다.
그러나 일반적인 함수 처럼 props에 직접 타입을 적용하는 것이 타입스크립트 또는 자바스크립트의 느낌과 비슷하고 다양한 경우의 수로 부터 비교적 좀 더 안전해 질 수는 있다.
참고: https://yceffort.kr/2022/03/dont-use-react-fc#reactfc%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80