Reputation: 2391
I need a parent component to know when it's child components have changed from collapsed to expanded and viceversa.
I don't want to keep that in the app state (Redux). I can't move the logic up to the parent component.
My components are:
I need B to know C is expanded, so that it isn't draggable while expanded.
I can't put the expanded/collapsed logic in B, because C should always be collapsible/expandable independently of if draggable.
Is there any simple way to accomplish this without needing to have the expand/collapse state of each item in the app state?
I have read about https://facebook.github.io/react/docs/context.html but seems still in experimental phase...
Upvotes: 0
Views: 72
Reputation: 231
You can keep the expanded state inside the C component and update the draggable state of the B component with a callback passed with the props of the C component. In this way both components keep their own state, no need to add the state on the A component or in you App state (the Redux one).
Here is an example: https://jsfiddle.net/snahedis/69z2wepo/28567/
var sampleList = [{id: 1, draggable: true},{id: 2, draggable: false}];
var Acomponent = React.createClass({
render: function() {
return (
<div>
{sampleList.map(function(component) {
if (component.draggable) {
return <Bcomponent key={component.id} />;
} else {
return <Ccomponent key={component.id} />;
}
})}
</div>
);
}
});
var Bcomponent = React.createClass({
getInitialState: function() {
return {
draggable: true
}
},
hasBeenToggled: function() {
this.setState({
draggable: !this.state.draggable
});
},
render: function() {
return <Ccomponent draggable={this.state.draggable} toggleExpandableCallback={this.hasBeenToggled} />;
}
});
var Ccomponent = React.createClass({
getInitialState: function() {
return {
expanded: false
}
},
toggleExpandable: function() {
this.setState({
expanded: !this.state.expanded
});
if (typeof this.props.toggleExpandableCallback === "function") {
this.props.toggleExpandableCallback();
}
},
render: function() {
return (
<div>
<div>I'm the C component and my expanded state is : {this.state.expanded.toString()}</div>
<div>{(this.props.draggable) ? "oh, and I'm draggable !" : "and I'm saddly not draggable"}</div>
<button onClick={this.toggleExpandable}>Change expandable state</button>
</div>
);
}
});
ReactDOM.render(
<Acomponent />,
document.getElementById('container')
);
Upvotes: 1
Reputation: 3230
A few ideas:
1) You can ALWAYS render B (A renders B's, each which wraps a C), but just disable the draggable behavior in B when it shouldn't be draggable (pass it in something like a isDraggable
to B). Then, C's collapsible state can be stored in B, and passed a prop to C, as B will always be there.
2) You can move all the state to A (not sure if this is what you mean by "app state")
It's hard to suggest without knowing more context. But in cases like this, there's almost a better way to break up your components / app state so that it doesn't feel "wrong."
Upvotes: 0