Software Engineering Asked by Christopher Francisco on December 19, 2021
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).
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
).
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 the hideOn
prop, because it doesn’t have a Header
within its children.Header
was one of Table
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?
It’s not a big issue to use cloneElement
on structured, nested data. It’s not surprising if td
elements renders differently compared to th
.
If you want to be explicit, you can always use the render props pattern. As an example, you can pass refs for calling imperative methods from the parent, or pass a callback to indicate that a child has changed. Something like this will suffice:
<Table rowCount={3} {...props}>
{({onHeaderChange, onRowChangeCallbackList}) => (
<Header onChange={onHeaderChange} />
// render rows
)}
</Table>
Answered by tonychow1997 on December 19, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP