Response.js changes the state of the topmost parent from a deeply nested child
I am using react-async along with node.js. React-async is used to consume response.js in an asynchronous way. To make ajax calls, I am using a super agent . The component PostList
is the top-most parent component. Thanks to its method, the setTopmostParentState
state of the component can be changed. I want to call this method from Comp4
. The parameter to this method will be obtained from the ajax call using the "super-agent" node middleware.
How can I change the state from Comp4? If it was a parent component and then a child component issue, then the state change method can easily be passed as a prop
child component. But multiple nesting makes it difficult to pass a parameter from a deeply nested child to the topmost parent.
Snippet of code:
var Comp4 = React.createClass({
clickHandler: function() {
request.get('/api/prods_find/' + cat_id + '/' + subcat_id,
function(resp) {
var prods_menu = resp.body;
* * * //CALL setTopmostParentState of the PostList component with the value prods_menu***
});
},
render: function() {
'<div onClick={this.clickHandler}>Target element</div>'
}
});
var Comp3 = React.createClass({
render: function() {
< Comp4 > < /Comp4>
}
});
var Comp2 = React.createClass({
render: function() {
< Comp3 > < /Comp3>
}
});
var Comp1 = React.createClass({
render: function() {
< Comp2 > < /Comp2>
}
});
var PostList = React.createClass({
mixins: [ReactAsync.Mixin],
getInitialStateAsync: function(cb) {
request.get('http://localhost:8000/api/posts', function(response) {
cb(null, {
prods_menu: response.body
});
});
},
setTopmostParentState: function(prods_menu) {
this.setState({
prods_menu: prods_menu
});
},
render: function() {
var prods = this.state.prods_menu.prods;
var menu = this.state.prods_menu.menu;
return (
< Comp1 > < /Comp1>
);
}
});
source to share
In your specific case, I would suggest passing in a function that your deepest child component should call.
var Comp4 = React.createClass({
clickHandler: function() {
request.get('/api/prods_find/' + cat_id + '/' + subcat_id,
function(resp) {
var prods_menu = resp.body;
this.props.updateParentState(prods_menu);
});
},
render: function() {
'<div onClick={this.clickHandler}>Target element</div>'
}
});
var Comp3 = React.createClass({
render: function() {
< Comp4 {...this.props} > < /Comp4>
}
});
var Comp2 = React.createClass({
render: function() {
< Comp3 {...this.props} > < /Comp3>
}
});
var Comp1 = React.createClass({
render: function() {
< Comp2 {...this.props} > < /Comp2>
}
});
var PostList = React.createClass({
mixins: [ReactAsync.Mixin],
getInitialStateAsync: function(cb) {
request.get('http://localhost:8000/api/posts', function(response) {
cb(null, {
prods_menu: response.body
});
});
},
setTopmostParentState: function(prods_menu) {
this.setState({
prods_menu: prods_menu
});
},
render: function() {
var prods = this.state.prods_menu.prods;
var menu = this.state.prods_menu.menu;
return (
< Comp1 updateParentState={this.setTopmostParentState} > < /Comp1>
);
}
});
But as you can see, this is rather cumbersome. This is why Flux was created. Using Flux, you can send a message to the Store containing the new data and the Store will notify your component by re-executing it.
You can read more about Flux here https://facebook.github.io/flux/
source to share
Not to say that this is great, but in a situation like this I use the PubSub library to link components. For example https://www.npmjs.com/package/pubsub-js .
In your top component, you can do this:
var EVENT_NOTIFY_TOPMOST = "EVENT_NOTIFY_TOPMOST";
componentDidMount: function() {
eventToUnsubscribe = PubSub.subscribe(EVENT_NOTIFY_TOPMOST, function( msg, data ){
console.log( data ); //logs "world"
});
}
componentDidUnmount: function() {
//don't forget this
PubSub.unsubscribe(eventToUnsubscribe )
}
And in your deepest child, you can do this:
PubSub.publish(EVENT_NOTIFY_TOPMOST , "world");
source to share