Context
When designing the API of a React component, you may decide to receive props in a more semantical way. Here's a simple example
<Modal headerTitle="foo" />
vs
<Modal>
<Header>Foo</Header>
</Modal
A more complex example would be this one, where we have a table and we need to set responsiveness:
const hideOn = { email: 'smDown'}
const data = [{ name: 'jonh', email: '[email protected]' }]
<Table hideOn={hideOn} data={data} />
vs
<Table>
<Header>
<HeaderCell>Name</HeaderCell>
<HeaderCell hideOn="smDown">Email<HeaderCell>
<Header>
<Row>
<Cell>John</Cell>
<Cell>[email protected]</Cell>
</Row>
</Table>
In both scenarios, I'd strongly argue the second design brings more benefits (but not going to discuss that here).
Pattern
Following the example above, in order to get the data for responsiveness of each of the tables Cell
, Table
need to run a children.find(child => child.type === HeaderCell).props.hideOn
and pass the value to the Cell
through cloneElement
.
Another example would be making a component API strict so that only certain components can be passed. In this example, the hacked div won't be rendered at all:
<Table>
<Header>
<div style={{backgroundImage: './foo.png', top: 0, position: 'absolute' }}>
Hacked div. Programmer was lazy to figure how to put a background
image in the header.
However, this hacked div won't get rendered
</div>
<Header>My Modal</Header>
...
</Table>
In this example, Table
can run a children.find(child => child.type ===
to find only valid children (Header
and Row
).
Problem definition
What if we needed to do some decoration or just DRYing up the code, like the following:
<Table>
<SharedHeaders />
<Row>
<Cell>John</Cell>
<Cell>[email protected]</Cell>
</Row>
</Table>
At this point, we see 2 problems:
Table
is no longer able to find thehideOn
prop, because it doesn't have aHeader
within its children.- Assuming
Header
was one ofTable
valid children,SharedHeader
is definitely not one of them.
This leaves me wondering whether the approach itself is fundamentally flawed, and I'm looking at the solution from the incorrect perspective.
I realize there are different options to solve the use case above (such as using the Context API), but I have other use cases where we work by finding a child with specific type, so I want to focus the question specifically on that practice, and its take on composition.
Is it an anti-pattern, when doing composition, for a component to search for a component with a specific type within its children in order to work?