Flowtype Props Passed to Children in React
Here's how to type props for a child component that has props cloned onto it.
This is for you, @nguyenmanh1507! :)
React Clone Props onto Children
In React, you can send props to children. This is a way for a parent component to provide a child component with data it didn't already have.
Many times this is because a parent and a child component work in tandem to create some larger UI.
A Radio Button Example
An example of this is a radio button group that has many radio buttons. They are tied together by a name
field, which allows the browser to know which radios belong to the group in order to cycle through them.
That code might look something like this:
import React from 'react'
const RadioOption = props =>
<label>
<input type="radio" value={props.value} name={props.name} />
{props.label}
</label>
const RadioGroup = props =>
<div class="radio-group">
{React.Children.map(props.children, child =>
child.type === RadioOption
? React.cloneElement(child, {
name: props.name
})
: child
)}
</div>
const WhereImUsingRadioGroups = _ =>
<RadioGroup name="blizzard-games">
<RadioOption label="Warcraft 2" value="wc2" />
<RadioOption label="Warcraft 3" value="wc3" />
<RadioOption label="Starcraft 1" value="sc1" />
<RadioOption label="Starcraft 2" value="sc2" />
</RadioGroup>
Flow Can't Infer the Cloned Prop
We can start type-checking this code with Flowtype by adding a comment to the top of the file:
// @flow
Flow immediately points out a problem to us:
9:
^ property `name`. Property not found in
9:
^ props of React element `RadioOption`
Flow can apparently infer that label
and value
are strings and passed in when RadioOption
is used. But it is confused about name
, which is cloned onto the RadioOption
children inside RadioGroup
.
Adding Types to RadioOption
We can provide some help to Flow by adding types to the props
passed to RadioOption
.
We can define them as:
type Props = {
label: string,
name?: string,
value: string
}
And adjust the RadioOption
signature to read:
const RadioOption = (props: Props) =>
// ...
Now we have no Flow errors!
The name
prop type is specified as name?
to indicate it's an optional object property. This is required, or we reverse our problem, confusing Flow as to why the name
is not included when
is called initially.
Are there other ways that you would handle typing cloned props in this case?