I want to pass down a prop from a parent component to all its children
, but only if the prop isn't already set explicitly on the child--the user of the components should be able to override the pass-down behaviour easily.
This is similar to How to pass props to {this.props.children}, although with the difference that I want "fallback" rather than "override" behaviour: I want existing props on the children to take priority.
Concretely, what I want to implement is a set of components Grid
, Grid.Row
, Grid.Column
, such that e.g.
<Grid size="big"> // A
<Grid.Row> // B
<Grid.Column> // C
<Grid size="small"> // D
<Grid.Column> // E
...
</Grid.Column>
</Grid>
</Grid.Column>
</Grid.Row>
</Grid>
would pass on size
from A to B to C, and from D to E. It's not passed on from C to D since we're explicitly providing our own size
in the D element.
Approaches
I can think of a few different ways to approach this.
Define a second "fallback prop"
With a second prop (say, fallbackSize
), we could set this prop unconditionally with React.cloneElement
the usual way. The child component then checks size
first, and if undefined it falls back to fallbackSize
(and then to whatever it would otherwise fall back to, if anything).
This strikes me as an undesirable solution since it introduces a new prop that doesn't actually represent anything, and merely serves to work around the lack of a nice way to provide a "fallback".
Inspect child for prop presence
I'm not sure if this is doable, but another "approach" would be to map with React.Children.map
as usual, but somehow inspect the child element for whether the prop is present or not, and if it isn't, add it with React.cloneElement
the usual way.
Compared to the previous solution, this feels a lot cleaner. However, it does require a reliable way of telling what props a rendered child already has, and I'm not sure offhand how one would do that (is it enough to just inspect child.props.propName
?)
Rely on the new Context API
React recently (as of mid-2018) introduced a new Context API that allows for managing state within a subtree of the React tree. This seems like an excellent use case for it, so I would argue this is the way to go.
That is, the parent would become a Provider providing the passed-down prop's value in its context, and the children would become Consumers of the same context, falling back to this if a prop isn't passed explicitly.
There are a couple concerns here too, though: it adds some amount of complexity, and I'm not sure if "passing down a single prop so that children know of it automatically" is minor enough that the Context API would be overkill. In fact, the Context API docs do provide the following notice:
Don’t use context just to avoid passing props a few levels down. Stick to cases where the same data needs to be accessed in many components at multiple levels.
In essence, I'm wondering what the most sensible and idiomatic approach would be here.