javascript - React state variable unexpectedly undefined when trying to pass as props -
i have react component hierarchy this:
agreementcontentwidget agreementtitlecontainer agreementtitle <-- ok, commentlist <-- problem here sectionscontainer
mounting agreementcontentwidget
:
<agreementcontentwidget agreement_id={85} />
requests widget load agreement 85.
var agreementcontentwidget = react.createclass({ getinitialstate: function() { return {agreement: []}; }, componentwillmount: function() { this.loadagreementdetails(); }, loadagreementdetails: function() { $.ajax({ url: "/agreements/" + this.props.agreement_id, type: 'get', datatype: 'json', success: function(agreement) { this.setstate({agreement: agreement.agreement}); }.bind(this), error: function(xhr, status, err) { console.error("/agreements/" + this.props.agreement_id, status, err.tostring()); }.bind(this) }); }, handleagreementupdate: function() { this.loadagreementdetails(); }, render: function() { return ( <div classname="panel panel-default"> <div classname="panel-body" id={"container_agreement_" + this.state.agreement.id}> <div classname="col-lg-12"> <agreementtitlecontainer agreement={this.state.agreement} onagreementupdate={this.handleagreementupdate} /> <sectionscontainer agreement={this.state.agreement} /> </div> </div> </div> ); } });
i pass agreement={this.state.agreement}
<agreementtitlecontainer>
render components comprising agreement's title.
inside <agreementtitlecontainer>
:
var agreementtitlecontainer = react.createclass({ handleagreementupdate: function() { this.props.onagreementupdate(); }, render: function() { return ( <div classname="row" id="container_title"> <agreementtitle agreement={this.props.agreement} onagreementupdate={this.handleagreementupdate} /> <commentlist commentable_type={"agreement"} commentable_id={this.props.agreement.id} /> <br /> </div> ); } });
<agreementtitle>
takes {this.props.agreement}
, it's got contents of agreement 85. renders , other operations expected. however, <commentlist>
has undefined
commentable_id
this.props.agreement.id
undefined (via debugger: this.props.agreement
undefined component).
so:
- why
{this.props.agreement}
defined<agreementtitle>
? - why undefined
<commentlist>
?
i know <commentlist>
works expected in other contexts value passed commentable_id
(e.g. commentable_id={42}
) rather object in this.state
(as above).
i noted <commentlist>
when tries get
request in loadcomments()
below:
var commentlist = react.createclass({ getinitialstate: function() { return {comments: []}; }, componentdidmount: function() { this.loadcomments(); }, loadcomments: function() { $.ajax({ url: "/comments/?commentable_type=" + this.props.commentable_type + "&id=" + this.props.commentable_id, type: 'get', datatype: 'json', success: function(comments) { this.setstate({comments: comments.comments}); }.bind(this), error: function(xhr, status, err) { console.error("/comments/?commentable_type=" + this.props.commentable_type + "&id=" + this.props.commentable_id, status, err.tostring()); }.bind(this) }); }, ... ... }
i error message failed get
get https://tinya-thedanielmay-2.c9.io/comments/?commentable_type=agreement&id=undefined 404 not found
which expect, id
(from this.props.commentable_id
above) undefined
. however, console.error
function prints out:
/comments/?commentable_type=agreement&id=85 error not found
so @ point of execution, this.props.commentable_id
seems defined now.
i'm thinking decision <agreementcontentwidget>
to:
get
agreement 85- set
this.state.agreement
agreement 85 details <-- - then proceed use
this.state.agreement
input props, e.g.agreement={this.state.agreement}
has issues.
architecturally, i'd retain get
agreement @ <agreementcontentwidget>
level , have retrieved agreement details propagate down.
what missing?
what you're initializing in getinitialstate
what's passed first time <agreementcontentwidget>
renders. think <agreementtitle>
works because re-rendered when agreement data backend, commentslist, being dependent on id load own data, error out before can render. doesn't know go out , data again because it's loading in componentdidmount
.
you should defer retrieval of comments until correct property. this, use react's componentwillreceiveprops(nextprops)
function , wait until agreement.id
exists, , not 0 before loading ajax.
so remove this.componentdidmount
commentlist , add this:
this.componentwillreceiveprops(nextprops){ if(nextprops.agreement && nextprops.agreement.id){ this.loadcomments(); } }
you should set proptypes can alerted these issues nice messages , provide self documentation code.
Comments
Post a Comment