id | title |
---|---|
function_components |
Function Components |
These can be written as normal functions that take a props
argument and return a JSX element.
type AppProps = { message: string }; /* could also use interface */
const App = ({ message }: AppProps) => <div>{message}</div>;
What about `React.FC`/`React.FunctionComponent`/`React.VoidFunctionComponent`?
You can also write components with React.FunctionComponent
(or the shorthand React.FC
- they are the same):
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
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
-
It provides an implicit definition of
children
(see below) - however there are some issues with the implicitchildren
type (e.g. DefinitelyTyped#33006), and it might be better to be explicit about components that consumechildren
, anyway.
const Title: React.FunctionComponent<{ title: string }> = ({
children,
title,
}) => <div title={title}>{children}</div>;
As of @types/react 16.9.48, you can also use React.VoidFunctionComponent
or React.VFC
type if you want to type children
explicitly. This is an interim solution until FunctionComponent
will accept no children by default (planned for @types/react@^18.0.0
).
React.VoidFunctionComponent
or React.VFC
type if you want to type children
explicitly. This is an interim solution until FunctionComponent
will accept no children by default (planned for @types/react@^18.0.0
).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
.
Minor Pitfalls
These patterns are not supported:
Conditional rendering
const MyConditionalComponent = ({ shouldRender = false }) =>
shouldRender ? <div /> : false; // don't do this in JS either
const el = <MyConditionalComponent />; // throws an error
This is because due to limitations in the compiler, function components cannot return anything other than a JSX expression or null
, otherwise it complains with a cryptic error message saying that the other type is not assignable to Element
.
const MyArrayComponent = () => Array(5).fill(<div />);
const el2 = <MyArrayComponent />; // throws an error
Array.fill
Unfortunately just annotating the function type will not help so if you really need to return other exotic types that React supports, you'd need to perform a type assertion:
const MyArrayComponent = () => (Array(5).fill(<div />) as any) as JSX.Element;