Reputation: 18746
Not referring to the magic props.children
, but can I force a child element to have specific attributes (or added values to an attribute) on the top-level element it produces? Example scenario:
const Button =
(props) =>
( <button type="button" id={props.id} className={['btn'].concat(props.classNames)}>{props.children}</button>);
would love to not have to do the classNames
prop, let the parent force extra classes down without child interaction/involvement/consent.
Even better if it would allow things, besides just extra css classes, but that's the current target.
Is it possible to do this to the children without them knowing?
Upvotes: 0
Views: 430
Reputation: 1582
This is probably what you're looking for (use ES6 spread operator):
const Button = (props) => (<button {...props}>{props.children}</button>);
It passes all the props that've been specified on Button
component down to <button>
element, so in case if you specify:
<Button className="my-class" id="10">submit</Button>
The <button>
element will receive: <button className="my-class" id="10" >submit</button>
Update: If you want to pass only some props and not all of them, then you might consider assigning an object to a top-level component and use it as props on a children one.
const Button = (props) => (<button {...props.data}>{props.children}</button>)
<Button data={{ id: 10, className: 'my-class' }}>submit</Button>
Upvotes: 1
Reputation: 5902
To answer your question, you can either use {...this.props}
or use refs to apply the class imperatively in componentDidMount
/ componentDidUpdate
of the parent class.
However I'd really try not to use either approach. The current version of React warns when unknown properties are set on a DOM node and {...this.props}
leads you often there. The imperative approach is also not good, because it breaks the functional data flow and basically makes using React obsolete.
I'd really try to be very explicit about what features / looks you want from a component and specify them strictly via props. That means also putting className
, style
and other attributes that seem trivial there. Often it's also helpful to use more semantic props: E.g. colorScheme="confirm"
, size="big"
, type="outline"
are examples what could be useful for a Button
component. That way it's possible to avoid some repetition when using the button across multiple places.
If you tell me more about your specific use case, I think there could be a good solution.
Upvotes: 0
Reputation: 5927
You can clone each child using React.cloneElement(), which allows you to merge in your own props...
React.Children.map(props.children, child => {
return React.cloneElement(child, { newProp: 1, otherProp: 'XYZ' });
});
...so, yours might look something like this:
const Button = (props) => {
const className = ['btn'].concat(props.classNames).join(' ');
<button type="button" id={props.id} className={className}>
{
React.Children.map(children, child => (
React.cloneElement(child, { className })
))
}
</button>
};
Upvotes: 1