1. React.FC
함수형 컴포넌트를 정의할 때 사용하는 타입이다. FunctionComponent의 줄임말이다.
❓ React 18 버전 이전까지 FC 사용을 지양했던 이유와 이제 다시 사용할 수 있는 이유는 무엇일까?
React.FC는 함수 컴포넌트의 props 타입을 간결하게 표현하기 위해 만들어졌다. 이를 통해 타입스크립트를 사용하는 프로젝트에서 함수 컴포넌트의 props를 명시적으로 지정할 수 있었다. 뿐만 아니라 props에 기본적으로 children이 포함하여, 컴포넌트에서 자식 요소를 손쉽게 다룰 수 있기를 의도했다.
import { FC } from 'react';
interface Props {
name: string
}
const Foo: FC<Props> = ({ name }) => {
return (
...
)
}
다음 코드와 같이 FC를 사용하지 않고 명확하게 지정해주는 방법으로 props를 넘겨받을 수도 있다.
interface Props {
name: string
}
const Foo = ({ name }: Props) => {
return (
...
)
}
React 18 버전 이전에, FC를 이용하면 컴포넌트 props가 type이 ReactNode인 children을 암시적으로 포함하면서 props의 타입이 명확하지 않아 의도하지 않게 동작하는 등의 문제가 있었다. 아래 코드를 보면 <App/> 컴포넌트에서 children을 다루고 있지 않음에도 Example에서 children을 넘겨주고 있으며, 어떤 런타임 에러도 발생하지 않는다.
const App: React.FC = () => {
return <div>hi</div>
}
const Example = () => {
return (
<App>
<div>Unwanted children</div>
</App>
)
}
React 18 업데이트로, FC의 암시적인 children이 삭제되었다.
❓ FC를 사용할 수 없는 환경은 무엇이고 어떻게 대처가 가능한가?
export default function App() {} 와 같은 함수 선언문에서는 FC를 사용할 수 없다. 이런 형태에서는 명확하게 지정해주는 방법으로 props를 넘겨받는다.
interface Props {
name: string
}
export default function Foo({ name }: Props) {
return (
...
)
}
❓ 그럼 FC와 명확하게 지정하는 방법 중에 무엇을 선택해야 할까?
가장 문제였던 FC의 암묵적인 children이 18 버전에서 사라졌기 때문에 어떤 것을 사용해야 할지에 대한 판단은 개발자의 몫이다. 다만, FC에는 이미 제네릭 타입이 포함되어 있기 때문에 props에도 제네릭이 필요한 경우 FC<Props<string>>과 같이 작성해줘야 해 복잡해질 수 있다.
2. React.ReactNode
모든 종류의 React 노드(React.ReactElement, string, null 등)를 포함한 최상위 부모 타입이다. 이 타입은 주로 컴포넌트의 children props로 사용되거나, 컴포넌트가 반환하는 JSX 요소들의 타입을 지정하는 데 사용된다.
import { ReactNode } from 'react'
interface Props {
children: ReactNode
}
const Component: FC<Props> = ({ children }) => {
return <div>{children}</div>
}
3. React.ReactElement
ReactElement는 ReactNode에 포함되어 있지만, ReactNode와 달리 createElement 함수를 통해 생성된 객체의 타입 즉, 윈시타입을 포함하지 않고 완성돤 JSX 요소만을 허용한다.
따라서 JSX 요소를 리턴하는 children에 대해서는 ReactElement 타입으로 지정해주어도 문제가 없다.
import { ReactElement } from 'react'
interface Props {
children: ReactElement
}
const Component: FC<Props> = ({ children }) => {
return <div>{children}</div>
}
또한 React.ReactElement와 같은 JSX 요소의 타입은 ts에서 자동 타입 추론을 해주므로, 필수 사용은 아니다.
4. React.PropsWithChildren
React 18 버전부터 FC 타입에서 children 속성을 제거하면서 PropsWithChildren이라는 새로운 타입을 제공하여 대체했다. 이전에는 props에 children: ReactNode 혹은 children: ReactElement을 적어주었지만, PropsWithChildren 타입을 사용하면 props에 children을 명시하지 않고 바로 사용할 수 있다.
import { FC, PropsWithChildren } from 'react'
interface Props {
name: string
}
export const Foo: FC<PropsWithChildren<Props>> = ({ name, children }) => {
return (
<>
<div>{name}</div>
<div>{children}</div>
</>
)
}
하지만 PropsWithChildren도 children을 넘겨주지 않아도 에러가 발생하지 않기 때문에 의도하지 않은 동작을 할 수 있다. 따라서, children을 반드시 받아야 하는 경우에는 PropsWithChildren을 사용하지 않는 게 좋다.
5. React.ChangeEvent<T>
폼 요소의 값이 변경될 때 발생하는 이벤트의 타입을 정의한다. input element에 사용한다. 제너릭으로 해당 ChangeEvent가 발생하는 HTMLElement 타입을 넣어 적용하면 된다. 주로 change 이벤트가 자주 일어나는 HTMLInputElement 타입이 유용하게 사용된다.
import { useState } from 'react'
const InputComponent: FC = () => {>('');
const [inputValue, setInputValue] = useState<string>('')
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value)
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={handleInputChange}
/>
<p>value: {inputValue}</p>
</div>
);
};
'Frontend > React' 카테고리의 다른 글
[React] useState 사용법과 동작원리 (1) | 2024.10.03 |
---|---|
[React] Redux 상태 관리 라이브러리 (1) | 2024.07.03 |
[React] fetch()로 API 호출 (GET, POST, PUT, DELETE) (0) | 2024.06.23 |
[React] useEffect를 사용하여 mount/unmount/update시 작업 설정하기 (0) | 2024.06.22 |
[React] json-server (0) | 2024.06.21 |