Function Components
These can be written as normal functions that take a props
argument and return a JSX element.
// Declaring type of props - see "Typing Component Props" for more examples
type AppProps = {
message: string;
}; /* use `interface` if exporting so that consumers can extend */
// Easiest way to declare a Function Component; return type is inferred.
const App = ({ message }: AppProps) => <div>{message}</div>;
// You can choose to annotate the return type so an error is raised if you accidentally return some other type
const App = ({ message }: AppProps): React.JSX.Element => <div>{message}</div>;
// You can also inline the type declaration; eliminates naming the prop types, but looks repetitive
const App = ({ message }: { message: string }) => <div>{message}</div>;
// Alternatively, you can use `React.FunctionComponent` (or `React.FC`), if you prefer.
// With latest React types and TypeScript 5.1. it's mostly a stylistic choice, otherwise discouraged.
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
// or
const App: React.FC<AppProps> = ({ message }) => <div>{message}</div>;
Tip: You might use Paul Shen's VS Code Extension to automate the type destructure declaration (incl a keyboard shortcut).
Why is React.FC
not needed? What about React.FunctionComponent
/React.VoidFunctionComponent
?
You may see this in many React+TypeScript codebases:
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
However, the general consensus today is that React.FunctionComponent
(or the shorthand React.FC
) is not needed. If you're still using React 17 or TypeScript lower than 5.1, it is even discouraged. This is a nuanced opinion of course, but if you agree and want to remove React.FC
from your codebase, you can use this jscodeshift codemod.
Some differences from the "normal function" version:
React.FunctionComponent
is explicit about the return type, while the normal function version is implicit (or else needs additional annotation).It provides typechecking and autocomplete for static properties like
displayName
,propTypes
, anddefaultProps
.- Note that there are some known issues using
defaultProps
withReact.FunctionComponent
. See this issue for details. We maintain a separatedefaultProps
section you can also look up.
- Note that there are some known issues using
Before the React 18 type updates,
React.FunctionComponent
provided an implicit definition ofchildren
(see below), which was heavily debated and is one of the reasonsReact.FC
was removed from the Create React App TypeScript template.
// before React 18 types
const Title: React.FunctionComponent<{ title: string }> = ({
children,
title,
}) => <div title={title}>{children}</div>;
(Deprecated)Using React.VoidFunctionComponent
or React.VFC
instead
In @types/react 16.9.48, the React.VoidFunctionComponent
or React.VFC
type was added for typing children
explicitly.
However, please be aware that React.VFC
and React.VoidFunctionComponent
were deprecated in React 18 (https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59882), so this interim solution is no longer necessary or recommended in React 18+.
Please use regular function components or React.FC
instead.
type Props = { foo: string };
// OK now, in future, error
const FunctionComponent: React.FunctionComponent<Props> = ({
foo,
children,
}: Props) => {
return (
<div>
{foo} {children}
</div>
); // OK
};
// Error now, in future, deprecated
const VoidFunctionComponent: React.VoidFunctionComponent<Props> = ({
foo,
children,
}) => {
return (
<div>
{foo}
{children}
</div>
);
};
- In the future, it may automatically mark props as
readonly
, though that's a moot point if the props object is destructured in the parameter list.
In most cases it makes very little difference which syntax is used, but you may prefer the more explicit nature of React.FunctionComponent
.