Function/Class Components
Adding Flow types to your React components is incredibly powerful. After typing your component, Flow will statically ensure that you are using the component in the way it was designed to be used.
Functional Components
Adding Flow types to a functional component is the same as adding types to a standard function. Just create an object type for the props and Flow will ensure that the props passed to the component match up with what is expected.
1import React from 'react';2
3type Props = {4 foo: number,5 bar?: string,6};7
8function MyComponent(props: Props) {9 props.doesNotExist; // Error! You did not define a `doesNotExist` prop. 10
11 return <div>{props.bar}</div>;12}13
14<MyComponent foo={42} />
9:9-9:20: Cannot get `props.doesNotExist` because property `doesNotExist` is missing in `Props` [1]. [prop-missing]
Adding Default Props to Functional Components
A nice pattern to add default props to functional components is to use
destructuring with default values.
By destructuring the props in the function parameter, you can assign a value to any props that are not passed
to the component (or passed with the value undefined
).
1import React from 'react';2
3type Props = {4 foo?: number, // foo is optional to pass in.5 bar: string, // bar is required.6};7
8function MyComponent({foo = 42, bar}: Props) {9 // Flow knows that foo is not null or undefined10 const baz = foo + 1;11}12
13// And we don't need to include foo.14<MyComponent bar={"abc"} />;
Class Components
To Flowify a class component, the type of the props can be passed as the first
argument to the React.Component
type. This will have the same effect as adding types
to the props
parameter of a function component.
1import React from 'react';2
3type Props = {4 foo: number,5 bar?: string,6};7
8class MyComponent extends React.Component<Props> {9 render(): React.Node {10 this.props.doesNotExist; // Error! You did not define a `doesNotExist` prop. 11
12 return <div>{this.props.bar}</div>;13 }14}15
16<MyComponent foo={42} />;
10:16-10:27: Cannot get `this.props.doesNotExist` because property `doesNotExist` is missing in `Props` [1]. [prop-missing]
Now wherever we use this.props
in our React component Flow will treat it as
the Props
type we defined.
Note: If you don't need to use the
Props
type again you could also define it inline:extends React.Component<{ foo: number, bar?: string }>
.
React.Component<Props, State>
is a generic type that takes two type
arguments: props and state. The second type argument, State
, is optional. By
default it is undefined
so you can see in the example above we did not include
State
. We will learn more about state in the next section...
Adding State
To add a type for state to your React class component: create a new object
type, in the example below we name it State
, and pass it as the second type
argument to React.Component
.
1import React from 'react';2
3type Props = { /* ... */ };4
5type State = {6 count: number,7};8
9class MyComponent extends React.Component<Props, State> {10 state: State = {11 count: 0,12 };13
14 componentDidMount() {15 setInterval(() => {16 this.setState(prevState => ({17 count: prevState.count + 1,18 }));19 }, 1000);20 }21
22 render(): React.Node {23 return <div>Count: {this.state.count}</div>;24 }25}26
27<MyComponent />;
In the example above we are using a React setState()
updater function
but you could also pass a partial state object to setState()
.
Note: If you don't need to use the
State
type again you could also define it inline:extends React.Component<{}, { count: number }>
.
Using Default Props for Class Components
React supports the notion of defaultProps
which you can think of as default
function arguments. When you create an element and do not include a prop
which has a default then React will substitute that prop with its corresponding
value from defaultProps
. Flow supports this notion as well. To type default
props add a static defaultProps
property to your class.
1import React from 'react';2
3type Props = {4 foo: number, // foo is required.5 bar: string, // bar is required.6};7
8class MyComponent extends React.Component<Props> {9 static defaultProps: {foo: number} = {10 foo: 42, // ...but we have a default prop for foo.11 };12}13
14// So we don't need to include foo.15<MyComponent bar={"abc"} />
Note: You don't need to make
foo
nullable in yourProps
type. Flow will make sure thatfoo
is optional if you have a default prop forfoo
.
If you add a type annotation to defaultProps
you can define the type as
1type DefaultProps = {2 foo: number,3};
and spread that into the Props
type:
type Props = {
...DefaultProps,
bar: string,
};
This way you avoid duplicating the properties that happen to have a default value.
Note: You can also apply this format of default props to functional components by adding a
defaultProps
property to a the component function. However, it is generally simpler to use the destructuring pattern described above.1function MyComponent(props: {foo: number}) {}2MyComponent.defaultProps = {foo: 42};