I'm using React, and I saw that one common practice is to bind the functions in the constructor, which I also want to use. Though, I don't exactly get how bind works for functions that take parameters. For example, I have something like this:
class MyClass extends Component {
constructor(props) {
super(props);
this.onListClicked = this.onListClicked.bind(this);
}
onListClicked(id) {
// performs some action
}
render() {
return (
// partially removed for brevity, value of myId comes from a loop
<ListItem onClick={ () => this.onListClicked(myId) } />
);
}
}
Now this works in my case, but I'm not taking advantage of bind fully. If I change the ListItem to <ListItem onClick={this.onListClicked} /> it doesn't work as expected. This would have worked if onListClicked didn't accept any parameters. But, in this case I don't know how to take advantage of bind. Any ideas?
your question has little to do with binding, and is really about how React handles callback props.
Every React event-listener function is passed an instance of React's SyntheticEvent object as its first parameter.
onClick={this.onListClicked} will call the onListClicked function and pass it one parameter: the SyntheticEvent object provided by React.
onClick={this.onListClicked.bind(this)} is the same as the last example. onListClicked.bind() returns a wrapped version of onListClicked with its context object set to this (which in your case is your React component because that's what this is set to when you do the binding). This wrapped version of your function still only receives one parameter: a SyntheticEvent object.
onClick={(e) => this.onListClicked(myId)} will call the anonymous fat-arrow function and pass it one parameter: a SyntheticEvent object, because the anonymous fat-arrow function is the callback and all callbacks get that parameter. This anonymous fat-arrow function ignores its own parameters, and calls this.onListClicked with the value of myId.
onClick={() => this.onListClicked(myId)} is the same as the last example, except we are ignoring the SyntheticEvent because we don't care about it.
onClick={this.onListClicked.bind(this, myId)}, as suggested in another answer, will wrap and call the onListClicked function and pass it TWO parameters: the first is myId (since bind is injecting myId as a parameter as well as setting the context to this) and the second is a SyntheticEvent object.
So: depending on what exactly you are doing inside of onListClicked, you may or may not need to bind it to your React component (or to some other context). Do you actually need variables and functions defined inside a particular object? Then bind your callback context to that object, and call this.foo or this.bar all you need. But if you don't need access to those sorts of things, there's no need to use bind just because it's there.
bind function takes a context as its first argument and takes your original function arguments as the next set of arguments after this. The "binded" (excuse me for the horrendous grammar!) function that is returned has the same arguments "binded" to it so when you call it, it will be called with the same set of arguments that it was bound with.
So essentially a <ListItem onClick={ () => this.onListClicked(myId) } /> should be replaced by a <ListItem onClick={this.onListClicked.bind(this, myId)} />
I, however, don't see a way for you to generate the function you need in the constructor itself since you won't have those arguments there to start with. You could loop over the array in the constructor itself and create those "binded" functions there only but that would be just a waste and a much elegant solution would be to use the above said method.
Read more about bind from MDN.
Related
In a class, why is the render method automatically bound to the component instance but custom methods e.g. event handlers aren't?
I understand using the bind keyword to make these event handlers work but was just trying to find an answer why "this" can be referenced in the render method but why it's also not automatically bound in event handler methods?
why is the render method automatically bound to the component instance
It isn't bound. It's just that react always calls the render function using the correct context.
For normal functions, the value of this is determined by how you call the function. In the following code, example. is the part that says what the value of this will be inside the function.
const example = {
value: 'abc',
printValue: function () {
console.log(this.value);
}
}
example.printValue(); // abc
But if you call the function in a different way, you can get a different value of this.
const example = {
value: 'abc',
printValue: function () {
console.log(this.value);
}
}
const temp = example.printValue;
console.log(temp === example.printValue); // true (they're literally the same function)
temp(); // undefined, or throw an exception depending on if we're in strict mode
So every time react calls the render function, it calls it the first way (or something equivalent to it), not the second way.
Citing React's docs:
You have to be careful about the meaning of this in JSX callbacks. In
JavaScript, class methods are not bound by default. If you forget to
bind this.handleClick and pass it to onClick, this will be undefined
when the function is actually called.
Defining them as arrow functions though, still at instance level, will change the scope to the component's instance. So all other methods like render, componentDidMount are part of the class' definition and are not event handler, which means this will point to the instance in them (the usual JavaScript behaviour for such methods).
And lastly, you can always call a method with a different scope with apply or call, changing what this refers to in those methods.
I'm a JS/React beginner who has read a few articles on the this keyword on JS, but remain confused.
Namely, I've consulted Tyler McGinnis's React and The Complete Javascript on Udemy.
This keyword is a fairly complex topic imo, but from these two sources I know .this refers to the global scope by default, but refers to the object in question when it is defined within a method. I also know that .call/apply/bind can give us a hint on what the .this refers to.
My question is, when do you actually write the .this keyword when you are writing your programs? The sources above seemed to focus on understanding why others might've used the keyword, but not necessarily when you need to do it. Thus, I always get confused when tutorials seemingly randomly throw in a this/bind etc everywhere
In terms of specific examples, I have :
1. One in the context of states:
I've encountered apps before learning about the .this concept which do not use the .this keyword. No specific examples for this, but shouldn't you use .this most of the time then?
Apologies if this is a silly question -- sometimes I wonder whether it is better to analyze/dissect the rationale for each part in coding or just to learn coding as just the way things are much like a child learns a language naturally without questioning grammar rules
In this example, we are passing down a prop called onDelete, but I do not understand why we need to bind. Does this mean we are binding the passed down onDelete to props.id which was also passed down?
The important part is you took the time to research. Personally I do not recommend using React to learn about this. When you extend a React component, your this prototype inherits from React.Component, so there's a lot of React-specific conventions there already. Instead, consider this example where I call this directly
function SimpleQueue({ size }) {
this.size = size
this.buffer = []
}
SimpleQueue.prototype.push = function(item) {
this.buffer.push(item)
if (this.buffer.length > this.size) {
this.buffer.shift()
}
return this
}
SimpleQueue is just a simple queue implementation using an internal array. You can think of this as a reference to the current instance of SimpleQueue, whatever that may be. I use this specifically in the example above to access the internal array as this.buffer. I can then use an instance of a SimpleQueue like so
const mySimpleQueue = new SimpleQueue({ size: 3 })
mySimpleQueue.push(1) // SimpleQueue { 1 }
mySimpleQueue.push(2) // SimpleQueue { 1, 2 }
mySimpleQueue.push(3) // SimpleQueue { 1, 2, 3 }
mySimpleQueue.push(4) // SimpleQueue { 2, 3, 4 }
Note: my example does not use class, but it is the same because classes are syntactic sugar for the prototype-based programming model
shouldn't you use .this most of the time then?
Yes, for class based react components, you should almost everywhere use this., for access props, state, handlers, calling methods etc.
constructor is an exception ... this.state is created, props are constructor argument.
Handlers declared using handleChange(e) {} syntax needs .bind(this) to be able:
to operate on this.state;
to use this.setState() (react component method derived from base class);
to use other methods defined in this component.
Usually event handlers are binded in constructor in the form like:
this.handleChange = this.handleChange.bind(this);
<button onClick={this.handleClick} />
Event handlers defined using ES6 'arrow syntax' fn = () => {} are autobinded to this.
Also handlers defined using 'normal function syntax' but assigned using 'arrow syntax' in render doesn't need binding:
<button onClick={(e) => this.handleClick(e)} />
Bad news - every render call crates new ref ... at least not optimal in react ... so ... use arrow declaration (or bind in constructor).
we are passing down a prop called onDelete, but I do not understand why we need to bind
Why? Probably passed handler not binded - rare requirement to bind handler to different object/component context (different this).
"this" is not a complex topic. people make it complex.
you have
handleTitleChange=(title)=>{
this.setState({})
}
When you say this.setState() you want this to refer the class component that you defined the handleTitleChange() inside. Arrow functions AUTOMATICALLY allow you to set “this” when the function is defined. That is why it is said that arrow functions are lexically bound to this. When our component is getting rendered by javascript for the first time, it checks inside and sees that there is handleTitleChange() points to arrow function. The moment it sees “this”, it is going to automatically bind “this” to the place where the arrow function is defined in the the first place. The context of that function is the TimerForm component.
But by default javascript does not set its scope of “this” on functions. "this" is dynamically scoped, it does not matter where the function is written, it matters how the function is called. That is why we have to actually explicitly state what context you want “this” to be for us. We want “this” to be our class component and the method in which we can do it is to define in our constructor(). If you write above code like this :
handleTitleChange(title){
this.setState({})
}
Now,in the above function this refers to the class but when you pass the reference to be called by another component or function, you are not passing its "this" anymore. New "this" will be assigned by object which calls "handleTitleChange(title)". We have to make sure that when we call handleTitleChange(title), its "this" value always points to TimerForm class. So we go to constructor(){}. Because our constructor() is the code that runs first before anything gets called. We want to make sure that the context of this is correct in all of our methods before any code gets written.
constructor(){
super()
console.log(this) // it will log TimerForm class
this.handleTitleChange=this.handleTitleChange.bind(this)
//bind(this) `this` refers to the TimerForm
}
bind() is a method on any function that returns a new function with a new execution context. now our handleTitleChange method learnt that this inside of it, will refer to the TimerForm class component.
to your 3rd question. props.onDelete is a function that's passed down, it's binding on this, which is the current execution context in <TouchableOpacity>, props.id is the argument of the onDelete function.
this is the old way, I believe an arrow function will do the same thing, () => props.onDelete(props.id)
And in react world/javascript land, function components/object destructing/arrow function are taking more ground these days, might be a reason you see less/none this in the codebase.
I'm a newbie in react (even in JS). I'm made the following code in my App class:
nameChangeHandler = (event, personId) => {
//method code
};
render()
{
<div>
{this.state.persons.map((person, index) => {
return <Person
// nameChangeHandler={(event) => this.nameChangeHandler(event, person.id)}
nameChangeHandler={this.nameChangeHandler.bind(this, person.id)}
/>
})}
</div>
}
I'm passing nameChangeHandler to Person component where I call it in onChange event in input tag (<input type="text" onChange={props.nameChangeHandler}/>)
Application works fine when I pass it in this way:
nameChangeHandler={(event) => this.nameChangeHandler(event, person.id)}
but it doesn't when I do it like this:
nameChangeHandler={this.nameChangeHandler.bind(this, person.id)}
It fails with an exception when I'm trying to acces event.target.value in nameChangeHandler method.
How can I pass event and argument to this method using bind() method instead of arrow function?
I've heard we should always use bind() approach over the arrow function because an arrow function approach could render component many times.
Is there any special use cases and differences between bind() and arrows functions?
It's a matter of timing.
When you use bind, the arguments map on to the function you are binding in the order you bind them followed by any that are passed to the new function.
When you use an arrow function, you are explicitly passing them in the order you determine.
Your function expects event to be the first argument, so when you use an arrow you function you pass event, person.id. However, when you bind you pass person.id (the first argument) and when the function is called with event you pass that (as the second argument).
This means you arguments end up the wrong way around.
Since you only have person.id when you call bind and you don't get event until later, the only way you can use bind for this is to change the original function so it accepts the arguments in a different order.
nameChangeHandler = (personId, event) => {
I have a method that passes up an argument in a nested view in Backbone, like such:
page.get('condition') ? this.trigger('someEvent', object) : this.trigger('someOtherEvent', object);
As I understand it, this code will pass object to 'someEvent' or 'someOtherEvent' as the first argument to the callback specified in the listener for that event.
My listener (in the parent view file) looks like:
this.parentView.on('someEvent', this.someFunction('extraArgument'), this);
By default, if the second parameter was just this.someFunction, I assume that the first argument to that function would be object.
My issue is that I want to pass 'extraArgument' in addition to the implicitly passed object.
As such, I structure the signature of this.someFunction like this:
someFunction: function(object, extraArg) {
...
}
However, debug statements within the function reveal that object is in fact the extraArgument I passed manually, and that extraArg is undefined in the scope of the function. How can I pass the extraArgument without overwriting the argument passed up from the child view?
When you say this:
this.parentView.on('someEvent', this.someFunction('extraArgument'), this);
you're calling this.someFunction right there when the argument list for this.parentView.on is being built. Then whatever this.someFunction('extraArgument') returns is bound as the callback for the 'someEvent' event. Your someFunction probably doesn't return a function so this on call won't do anything useful.
Sounds like you want to partial evaluate this.someFunction so that you create a new function that is just like this.someFunction but the first argument is always 'extraArgument'. Underscore offers _.partial for just that purpose:
partial _.partial(function, *arguments)
Partially apply a function by filling in any number of its arguments, without changing its dynamic this value.
So you'd say:
this.parentView.on(
'someEvent',
_(this.someFunction).partial('extraArgument'),
this
);
You can also use _.bind for this if you want to set the this along the way.
What does the 'function' do in the following?
$('.event-row').on('mouseover',function(){
arc.event_handler.event_row_over();
});
$('.event-row').on('mouseover',arc.event_handler.event_row_over );
There's a very important difference.
The first one will call the function with the context its this value as the event_handler object.
The second one will call the function with the context its this value as the DOM element to which the handler is bound.
So the first one preserves the expected calling context this value, which may be required by the function.
In the first case with the anonymous function this inside that function is bound to the DOM element that caused the event. This is a convention that is common in browsers and also done when binding events natively. When calling arc.event_handler.event_row_over(); however, this is re-bound to arc.event_handler inside event_row_over; as it's called as an object method and in such a case this points to the object on which the method was called. The method will be called without any arguments.
In the second case you register the function arc.event_handler.event_row_over for the event. When called jQuery sets this to the related element so inside event_row_over, this points to that element. arc.event_handler is not available in there unless there is some other variable that points to it. jQuery also passes the event object as the first argument so the method is called with that argument.
Usually object methods expect this to be their object, so in almost every case you want to use the anonymous function to wrap the call. In case the element matters, pass this as an argument to the method.
Another way, without an anonymous function, would be using the bind() method every function has:
$('.event-row').on('mouseover', arc.event_handler.event_row_over.bind(arc.event_handler));
However, only modern browsers support this natively.
In the first case you are enclosing the function call in an anonymous function.
In the second case you are just assigning the function pointer..
First off, it seems like there is an extra dot in there.. arc.event_handler.event_row_over.(); should probably be just arc.event_handler.event_row_over();
And all the anonymous function does is it calls a member function named event_row_over of the arc.event_handler object; and it doesn't return anything.
The 'function' keyword will creates a new closure and encapsulate the scope. Good article on closures https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures.
The first case, you have an additional function wrapper. This is useful when you want to do something else before calling the real event handler 'arc.event_handler.event_row_over()' for example you may do something like below:
$('.event-row').on('mouseover',function(){
doPreEventHandling();
arc.event_handler.event_row_over();
doPostEventHandling();
});
On the other hand you may even extract that annonymous function to be a named function and call as below:
var eventHandler = function(){
doPreEventHandling();
arc.event_handler.event_row_over();
doPostEventHandling();
};
$('.event-row').on('mouseover', eventHandler);
All above will be just similar in behavior, but more wrapper functions you have more abstraction you gain. But it will compromise performance and sometimes readability.
The context/scope of the function will not be the same.
Also, with the second one,
$('.event-row').on('mouseover',arc.event_handler.event_row_over );
you're getting the event object as an argument.