Reputation: 1691
I'm going to use an example to explain the functionality I'm looking.
const Grandparent = React.createClass({
render: function(){
return (<div>
<Parent>
<button className={this.props.parentClassName} />
</Parent>
<div>
)
}
});
const Parent = React.createClass({
render: function(){
const childrenWithProps = React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {parentClassName: 'Murphy'});
});
return (<div>
{childrenWithProps}
</div>)
}
});
What I would like is for the Parent component to intercept the props.parentClassName set in GrandParent and change it, or create it if it doesn't exist.
Inorder for the button to receive the correct parentClassName I have to create a custom Button component to receive the props just from the Parent component, like so
React.createClass({
render: function(){
return (<button className={this.props.parentClassName} />)
}
});
I want to avoid this if possible, because it extracts away code that I would like to be visible when declaring the initial component.
So I would like this
React.createClass({
render: function(){
return (<div>
<Parent>
<button className={
//From Parent Component and not the GrandParent Component
this.props.parentClassName
} />
</Parent>
<div>
)
}
});
instead of this
React.createClass({
render: function(){
return (<div>
<Parent>
<Button />
</Parent>
<div>
)
}
});
const Button = React.createClass({
render: function(){
return (<button className={this.props.parentClassName} />)
}
});
Where the props.parentClassName is returned from the <Parent>
component, and not the <GrandParent>
component.
Upvotes: 3
Views: 2923
Reputation: 3702
What I would like is for the Parent component to intercept the props.parentClassName set in GrandParent and change it, or create it if it doesn't exist.
A component cannot intercept props from its parent because it has no access to its parent, only to its children!
I'm still don't clearly understand what you want to achieve... Does the following code do what you want?
import _ from 'underscore';
import React from 'react';
class Grandparent extends React.Component
{
render() {
return (
<div {... this.props}>
<Parent>
<span>hello</span>
<span>welcome</span>
<span className="red">red</span>
</Parent>
</div>
);
}
}
// Parent component will add ``className="border"`` to each its
// child without ``className`` property.
class Parent extends React.Component
{
render() {
return (
<div {... this.props}>
{_.map(this.props.children, (v, k) =>
React.cloneElement(v, {className: v.props.className || 'border', key: k}))}
</div>
);
}
}
Upvotes: 1
Reputation: 1380
I think I understand what you are trying to do. I am sure this is not the answer you are looking for, but React was not designed that way. You could (you really shouldn't, but you could) use a flux container and save the parent's className in your flux store and call it in the class you were showing above.
I would reconsider how to do this the React way rather than using Flux or trying to make a hacky workaround.
In my experience, when rendering a custom component like this:
return (
<customComponent>
<button />
</customComponent>
);
You are always better off including <button />
as a prop like this:
return (
<customComponent buttonElement={<button />} />
);
and rendering {this.props.buttonElement}
where you want it in the render function of the customComponent
class. If you are not going to pass a button to every instance of customComponent
, you could do this in the render function of customComponent
:
if(typeof(this.props.buttonElement) !== "undefined") {
var buttonElement = this.props.buttonElement;
}
else {
var buttonElement = "";
}
render (
{buttonElement}
);
Upvotes: 2