Reputation: 4107
While building my first reactjs component, I got the familiar "undefined is not a function" when trying to use a helper (makeWorkSiteUrl
) because the this
scope had changed away from being that of the component.
Of course, I just did what most JS developers would do and declared that=this
before I made my function call to solve the problem.
However, it occurred to me that this is probably a common problem. So there might be a 'better' or 'react' way of achieving the same thing. Or, it may be an indication of poor design of this component. Is there a style or method that is preferred or available instead of that=this
to access a components internal functions/properties?
"Undefined is not a function":
var WorkSiteQuickList = React.createClass({
propTypes: {
data: React.PropTypes.object.isRequired
},
render() {
var workSiteNodes = this.props.data.work_sites.map(function (worksite) {
var linkUrl = this.makeWorkSiteUrl(worksite.id) //Fail
return (
<WorkSiteQuickListItem workSiteName={worksite.name} linkUrl={linkUrl} />
);
});
return (
<div>
{workSiteNodes}
</div>
);
},
makeWorkSiteUrl(workSiteId) {
return "/worksite/"+ workSiteId;
}
});
Works as expected:
var WorkSiteQuickList = React.createClass({
propTypes: {
data: React.PropTypes.object.isRequired
},
render() {
that = this;
var workSiteNodes = this.props.data.work_sites.map(function (worksite) {
var linkUrl = that.makeWorkSiteUrl(worksite.id) //OK
return (
<WorkSiteQuickListItem workSiteName={worksite.name} linkUrl={linkUrl} />
);
});
return (
<div>
{workSiteNodes}
</div>
);
},
makeWorkSiteUrl(workSiteId) {
return "/worksite/"+ workSiteId;
}
});
I'm sure this question will be closed, but I'd rather ask it than miss a critical part of the "framework".
Upvotes: 2
Views: 314
Reputation: 35900
Here are some common patterns to deal with this
scoping:
Utilizing an es6 transpiler (like the JSX transformer that you're currently using, or babeljs which happens to support JSX), use arrow functions which are scoped to the outer context (aka lexical scoping).
this.props.data.work_sites.map( (worksite) => { .... return ... } )
Pass in this
as the second argument of Array#map
Chain bind onto the function you pass into Array#map
function() {}.bind(this)
Update: I've had a lot of trouble lately with =>
, this
resolving to window
when paused at a breakpoint in the chrome dev tools within the render()
method. Originally I thought it was a babeljs bug. However, turns out it's actually a failure of the dev tools ability to understand that source maps actually replace this
with _this
.
Upvotes: 3