Send Props to Children in React
In React, you're always making components. Sometimes components are standalone. Other times, you'll have components that can nest children components. Sometimes you'll want to send properties to the children components from the parent as often as a doting parent wants to send packages to a child missionary. It's possible, it's simple, and it's not documented super well. Here's one method.
Updated: 29 Apr 2016 for React 15.x.
Children Components
When parent components are rendered, they have access to a special property, this.props.children
. It's like an Angular ng-transclude
or an Ember yield
. Children components are generally rendered something like this:
function Parent(props) {
return (
<div id="iAmParentHearMeRoar">
{props.children}
</div>
)
}
The generic example above shows simply how to render children, props
untouched, within a parent component. Sometimes, however, a parent wants to bequeath its children with extra properties. How will we make that happen?
Setting Child Props
props
are meant to be immutable. But, in order for us to send props
values to our children, we're going to essentially loop through our children and set props on them as a part of our parent render
function.
Deep breath. It's ok. The children that we'll loop through aren't mounted component instances. They are, instead, descriptors. These descriptors have all the props
attributes that we've declared should be put on the components, but they haven't been rendered yet. Because of this, we can change props, and it's ok. We're not mutating what has rendered. The data still hasn't flowed to the children. We're still effectively still riffing on the logic of what the children components should really be when they're eventually mounted.
Looping on Children Components
this.props.children
is a funny property. It's special in more ways than one. The things that might trip us up in looping is that even though it sounds like a plural thing, meaning an array, sometimes it's a singular object. To help avoid potential problems, React gives us a helper, React.Children
. It has a few functions for array iteration, such as map
and forEach
that help account for the potential forms of this.props.children
.
Functional Modifications
Immutable data is a big part of functional programming. This means that when we 'mutate' the props, we want to mutate on a clone of the child component without affecting the original. There's an input, there's an output, and the input is untouched. Once we have our cloned children components as we want them, we'll render those instead. React offers another great helper for cloning components and setting properties in a single function, React.cloneElement
.
Checking Child Type
It's a generally-useful thing to be able to tell what the React class type of a component object is. It's an applicable skill in terms of looping through child components because we might not want to modify the properties of all types of children. Each React component class has a type
attribute accessible via MyComponent.type
. This attribute is also available on component descriptors.
A Child CheckOption Example
To bring this all together and illustrate the concepts, let's say we created a RadioGroup
component that could take one or many RadioOption
child components. In raw html, which is what our component will eventually render, input
s with type checkbox
need to all have the same name
attribute value to work well as toggles within the group. But this is something that React can help us not have to duplicate. We'll instead put a name
property on the parent RadioGroup
and have it transfer it as a property on all its children. The implementation might look like this:
import React from 'react'
function RadioOption(props) {
return (
<label>
<input type="radio" value={props.value} name={props.name} />
{props.label}
</label>
)
}
function renderChildren(props) {
return React.Children.map(props.children, child => {
if (child.type === RadioOption)
return React.cloneElement(child, {
name: props.name
})
else
return child
})
}
function RadioGroup(props) {
return (
<div class="radio-group">
{renderChildren(props)}
</div>
)
}
function WhereImUsingRadioGroups() {
return (
<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>
)
}
See this example on jsbin.
In this example, where the parent RadioGroup
has the name
prop, it will be given to each of the children so their name
prop will match and the radio group will work as expected. Thus, the hearts of the children are turned toward their fathers.
Is there a better way to do this? How have you been sending props
to children?