Reputation: 339
I'm using react to retrieve data from parse, manipulate it in my own function, and then update a component in the render.
The problem is that I can't update the state within my own, convoluted function unless I attach a string of bind(this). The entire component looks like this:
React.Component({
getInitialState: function () {
return{
isloading:true
}
},
componentDidMount: function(){
this.myStupidFunction()
},
myStupidFunction : function(){
(
(
(nested parse queries that eventually ...
return an object and set isloading:false).bind(this))
.bind(this))
.bind(this)
},
render: function (){
if (this.state.isloading) {
return(
<Text "...isloading"/>
)
} else {
return(
...actually return important stuff...
)
}
}
})
What is the smarter way to do this? Do I need to really .bind(this) for every nested function?
Upvotes: 1
Views: 280
Reputation: 93
Using ES7 Property Initalizer Syntax, currently implemented in Babel.
The key is the methodName = () => { //method return }
You can read more here.
import React from 'react';
export default class Note extends React.Component {
constructor(props) {
super(props);
this.state = {
editing : false
}
}
render() {
const editing = this.state.editing;
return (
<div>{ editing ? this.renderEdit() : this.renderTask() }</div>
)
}
renderEdit = () => {
return (
<input type="text"
className="edit-input"
autoFocus={true}
defaultValue={this.props.task}
onBlur={this.finishEdit}
onKeyPress={this.checkEnter} />
)
}
renderTask = () => {
const onDelete = this.props.onDelete;
return (
<div onClick={this.edit}>
<span className="task-body">{this.props.task}</span>
{ onDelete ? this.renderDelete() : null }
</div>
)
}
renderDelete = () => {
return (
<button className="delete-btn" onClick={this.props.onDelete}>x</button>
)
}
edit = () => {
this.setState({
editing : true
})
}
checkEnter = (e) => {
if(e.key === "Enter") {
this.finishEdit(e);
}
}
finishEdit = (e) => {
this.props.onEdit(e.target.value);
this.setState({
editing : false
})
}
}
// Note: Sample class from project above.
Upvotes: 0
Reputation: 29999
There are a few ways to maintain the context of your component.
If you use ES6 arrows to define your functions. Arrow functions force the inner context of this to be the same as the outer context, regardless of how the function is called.
parse.find({
success: results => {
// this is correct
console.log(this);
}
});
I think this is the most elegant solution, but not all browsers support arrow functions yet.
React automatically binds this
into each of the top level methods on your component. They are always guaranteed to have the correct context.
onSuccess: function() {
// this is correct
console.log(this);
},
componentWillMount: function() {
parse.find({
success: this.onSuccess
});
}
This is also fairly elegant, in my opinion. It lets React deal with the messiness of context whilst you just write code. However, it can mean that you end up with far too many methods at the top level of your component, so use it sparingly.
Some functions, such as map
allow you to optionally pass a context to use as this
as a final argument. This allows you to maintain the correct context without .bind(this)
.
data.map(function() {
console.log(this);
// this is correct
}, this);
This only works for some methods, so it's not really a universal solution.
this
Create a reference to this and use that instead.
var __this__ = this;
parse.find({
success: results => {
// __this__ is correct
console.log(__this__);
}
});
This hack has been around forever in Javascript, but I don't think it's a great way to solve the problem.
For those who like to Javascript on the edge, you could also achieve this using the ES7 function bind syntax proposal — currently implemented in Babel.
parse.find({
success: this::function(results) {
// this is correct
console.log(this);
}
});
This requires using experimental proposal stage features of ES7. You may not want to start using it yet, but it's definitely interesting to be aware of. The value on the left hand side will be bound into the function on the right, as this
.
Upvotes: 3
Reputation: 3706
one solution could be using local variable
myStupidFunction:function(){
var that=this
ParseReact.Mutation.Create('Place', {
name: 'New Place',
user: Parse.User.current()
})
.dispatch()
.then(function() {
that.refreshQueries();
});
}
Upvotes: 0
Reputation: 19857
Use a closure at the beginning of the function to capture this
. It will be usable in any nested structure. The conventional names for such a closure are self
_this
and that
. I prefer self
.
myStupidFunction : function(){
var self = this;
someAsyncCall(1,2, function(result) {
//some nested stuff
anotherAsyncCall(1,2 function(innerResult) {
self.setState(innerResult);
});
});
}
Upvotes: 0