What is the difference between this.function and function call in React - javascript

I am React beginner. I've seen some code in a React project that I did not understand.
What is the difference between this.function and the following function call in a React event handling prop?
<button onClick={this.clickHandler}></button>
<button onClick={() => this.clickHandler()}></button>
Can anyone kindly explain to me what the difference is in the example above?

This is Traditional :-
var obj = {
count : 10,
doSomethingLater : function (){
setTimeout(function(){ // the function executes on the window scope
this.count++;
console.log(this.count);
}, 300);
}
}
obj.doSomethingLater(); // console prints "NaN", because the property "count" is not in the window scope.
And this is Arrow :-
var obj = {
count : 10,
doSomethingLater : function(){ // of course, arrow functions are not suited for methods
setTimeout( () => { // since the arrow function was created within the "obj", it assumes the object's "this"
this.count++;
console.log(this.count);
}, 300);
}
}
obj.doSomethingLater();
More information

The latter creates a useless anonymous wrapper function around this.clickHandler.

the first one creates an anonymous function around your first function.
let's turn it into vanilla javascript (a bit modified though)
<! -- equivalent to <button onClick={() => this.clickHandler()}></button> -->
<button id="btn-2">button 2 </button>
<script>
document.querySelector("#btn-2").addEventListener("click", function()
{
// the above function will be created
// executing some code
clickHandler()
})
</script>
so the function nesting is just useless as you create a function whose sole purpose is to launch another function. The best way would be to do this
<! -- equivalent to <button onClick={this.clickHandler}></button> -->
<button id="btn-1">button 1 </button>
<script>
// instead of an anonymous function we directly inject the function to be lauched.
document.querySelector("#btn-1").addEventListener("click", clickHandler)
</script>
Try to avoid function nesting as it may in some extreme case overflow your memory although it is use less. Arrow function ( => ) is a javascript ES6 feature widely used by React.

Read this:- https://reactjs.org/docs/handling-events.html
The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.

Related

Why v-on:click="method()" is treat as a method declaration like the v-on:click="method"?

Consider this example https://codesandbox.io/s/1yvp4zz5x7?module=%2Fsrc%2FApp.vue
<template>
<div>
<button v-on:click="method">Greet1</button>
<button v-on:click="method()">Greet2</button>
</div>
</template>
<script>
export default {
methods: {
method() {
alert('Hello');
}
}
};
</script>
Both buttons will work exactly the same (I'm aware of passing event in the first example) despite the fact that in v-on:click in "Greet1" there is method declaration and in "Greet2" there is method invokation.
Shouldn't "Greet2" display alert during component rendering phase and this button shouldn't work on clicking since I didn't return function in method()?
Why there is this mechanism here and how it works?
The method is not called immediately, because before the template is ever rendered, it is compiled into a function. During the compilation process, the v-on click expression is parsed by Vue and handled in two separate ways. Essentially, what happens when the template is compiled in the case of
<button v-on:click="method">Greet1</button>
is that the click handler is set directly to method. In the case of
<button v-on:click="method()">Greet2</button>
the click handler is set to
function($event) { method() }
The entire compiled render function is wrapped in a with(this) so that method() and other things that are declared that way are resolved properly.
Here is a little snippet from the generated code that shows how this is decided.
var fnExpRE = /^\s*([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/;
var simplePathRE = /^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?']|\[".*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*\s*$/;
...many lines omitted...
var isMethodPath = simplePathRE.test(handler.value);
var isFunctionExpression = fnExpRE.test(handler.value);
if (!handler.modifiers) {
if (isMethodPath || isFunctionExpression) {
return handler.value
}
return ("function($event){" + (handler.value) + "}") // inline statement
}
If you read through the code of the above link, the function in question is genHandler (for this particular version of Vue, which is 2.5.13).

In this context, what exactly does $('id').on('click', this.method.bind(this)) do?

Here is the app I'm referring to:
I am trying to fundamentally understand the bind method in Javascript.
My understanding when I play around with it in the console is that bind returns a copy of the function, with "this" bound to whatever you pass into bind.
function logThis(){
console.log(this)
}
logThis.bind({today: 'Tuesday'})
//Will return a copy of the logThis function, with 'this' set to the
{today:'Tuesday'} object. The code does not run right away though.
var explicitlyLogThis = logThis.bind({today: 'Tuesday'});
explicitlyLogThis(); //This will run the code and display the {today: 'Tuesday'} object to the console.
This is my understanding so far. I understand that to actually run this new function that has 'this' explicitly bound using the bind method, you need to set it to a variable and then run it.
I see a contradiction when I look at the app in the above link. If you look at the bindEvents method on line 56, we have .on('keyup', this.create.bind(this)). I understand that we have to set 'this' to App when we run the create method because jQuery defaults to setting 'this' to the jQuery object itself. So this line is actually the same as: $('#new-todo').on('keyup', App.create.bind(App)).
That isn't where my confusion is. My question is:
How exactly are these copies of the functions with 'this' set to App actually being called? The app does not set them to a variable and then call that variable the way I had to when I was working in the console.
It just invokes the bound functions directly as soon as an event occurs on one of the jQuery elements. But I thought writing it this way would just return a copy of the function, and not run the function itself, if I am basing my assumptions on what I have figured out in the code I wrote above. I thought in order to invoke the function immediately, you would need to use call or apply.
I also realize that the app runs the bindEvents method when it starts (see line 46). So I understand that when you start the app, copies of the various functions are created with the correct 'this' bound to the functions. But...when/how do they actually get invoked without assigning them to variables? How are these copies accessed?
I think I have a flawed understanding of the bind method, so I would love some help. Thanks!
It sounds like you understand bind well enough. Perhaps there is some confusion with passing anonymous functions. As you know calling bind returns a new function and this can optionally be stored as a variable or passed as a function argument.
In the example below btn1 accepts a bound function as you've seen. This could also be written in a more long hand fashion with btn2. They're identical. btn3 doesn't receive a bound function, when its clicked its context is the button element, this looses all visibility of MagicalApp fucntions.
<button id="example1">button one bound</button>
<button id="example2">button one bound</button>
<button id="example3">button two unbound</button>
<script>
class MagicalApp {
add() {
console.log('this could do addition');
}
}
const app = new MagicalApp();
function contextOfEvent(event) {
console.log('contextSensitive', this.add)
}
const btn1 = document.querySelector("#example1");
btn1.addEventListener('click', contextOfEvent.bind(app));
const btn2 = document.querySelector("#example2");
const btn2ClickHandler = contextOfEvent.bind(app)
btn2.addEventListener('click', btn2ClickHandler);
const btn3 = document.querySelector("#example3");
btn3.addEventListener('click', contextOfEvent);
</script>

Differences in arrow function and no arrow function in ReactJS?

I am currently very confused about when should we use arrow function and when we should not. I did the search about this but still I'm not clear. For example, I create a button to count clicks, the code is like below:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {counter: 0};
}
buttonPressedIncrease = () => {
this.setState((prevState) => {
return {counter: prevState.counter + 1}
});
}
render() {
return (
<div>
<div>Counter: {this.state.counter}</div>
<button onClick={this.buttonPressedIncrease}>+</button>
</div>
);
}
}
When I use arrow function on the button like this: onClick={() => this.buttonPressedIncrease}, the function does not work like I use in the code above.
Anyone can explain for me this problem? When will arrow function work and when will it not?
Many thanks in advance.
You have already defined buttonPressedIncrease as a "fat-arrow" function:
buttonPressedIncrease = () => {
This means that if you write () => this.buttonPressedIncrease, you are passing an anonymous function that returns the function. onClick wants a function that does something, not a function that returns another function.
Since you are using a fat arrow when you define the function, this is already bound correctly, so you should just pass the name of the function:
onClick={this.buttonPressedIncrease}
Sometimes in JSX you see onClick={() => someFunction()} (note that someFunction() is being called, unlike in your example), which may be the source of your confusion. This is another way to keep the right this in scope but comes at the cost of creating a new function every time your render method is called. For this reason, the above approach is preferred.
In short, event listeners such as onClick expect to be given a reference to the function you want to invoke.
With this in mind:
onClick={this.buttonPressedIncrease}
is correct because this.buttonPressedIncrease is a reference to a function and it is the one you want to run.
However,
onClick={() => this.buttonPressedIncrease}
is incorrect because while () => this.buttonPressedIncrease is a function reference, it is not the function you want to execute. You don't want to execute the anonymous function () => this.buttonPressedIncrease, you want to execute this.buttonPressedIncrease. Remember that functions are only invoked with (). Ignoring the parenthesis only returns their reference. That's why this won't work - the anonymous function doesn't invoke the wanted function.
Though, if you want, you could do:
onClick={() => this.buttonPressedIncrease()}
because the anonymous function will invoke the wanted function. Though I'd stick to the former solution.
Please note that arrow function is just a different syntax of the traditional javascript function(pseudo code):
function funcName(arg1,arg2) {
return returned_exp/value
}
Arrow representation
const funcName = (arg1,arg2) => returned_exp/value
Now, note that the returned expression can be a function here.
So in your code
<button onClick={this.onClickHandler}></button>
you just pass a function that needs to be executed onClick. Where as in below code
<button onClick={() => this.onClickHandler()}></button>
you pass a function which, when executed executes the function this.onClickHandler ( a set of open and closed parenthesis calls a function).
So generally we use the latter approach when we need to pass some data/object/function to the onClickHandler as arguments like so:
<button onClick={() => this.onClickHandler(this.props.requiredStuff)}></button>
Hope this helps !

How to change a state variable, calling self methods, and handling window functions while still using pure functions?

I am currently looking into utilizing mostly pure functions in my code. I realize the benefits of this. However, I'm wondering what the best practice is when updating a state variable, calling methods defined within a module, and how to handle window functions.
Using the example below, let's say I have a module, MyModule.
The MyModule.calculate function is pure, so no worries there.
The MyModule.trackSomething function however is updating the MyModule.count to keep track of it for use in the event handler, used in MyModule.assignEventHandlers function. This is not pure because it is using an outside reference to a variable. Even if I refactor to make count an object and pass it in as a parameter to MyModule.trackSomething, I'd still be altering the value through reference, making it impure.
In the MyModule.assignEventHandlers function, I'm using global window object functions. This makes it impure because I'm referencing outside functions. Should the window object be passed by reference when calling functions it has?
In the MyModule.init function, I'm calling the MyModule.assignEventHandlers function. I guess this makes it impure as well since MyModule.assignEventHandlers is an outside reference.
So my question is: What is the best way to handle the last 3 bullet points?
Any advice is much appreciated. Thanks!
const MyModule = {
calculate(a, b) {
return a + b;
},
count: 0,
trackSomething() {
MyModule.count += 1;
},
assignEventHandlers() {
// assign event handlers to some DOM elements
window.document.getElementById('my-ele').addEventListener('click', () => {
window.alert(MyModule.count);
MyModule.trackSomething(MyModule.count);
});
},
init() {
MyModule.assignEventHandlers();
}
};
I think when we came out with a solution, instead of just focus on pure and impure function, it's better to focus on practicability as well. It's okay to have impure function.
Here is another version of the implementation using RxJs - a reactive js lib. Also using ES6 class instead of module. Take a look at action and action2. Both produce same result in different ways.
In my opinion, action is good enough. Don't need to make everything super pure.
class MyClass {
constructor(elementId) {
this.ele = document.getElementById(elementId);
this.click$ = Rx.Observable.fromEvent(this.ele, 'click');
this.count = new Rx.BehaviorSubject(0);
}
calculate(a, b) {
return a + b;
}
action() {
window.alert(this.count.getValue());
const nextVal = this.calculate(this.count.getValue(), 1);
this.count.next(nextVal);
}
action2(log, subject, method) {
log(subject.getValue());
const nextVal = method(subject.getValue(), 1);
subject.next(nextVal);
}
}
const a = new MyClass('my-ele1');
a.click$.subscribe(() => a.action2(window.alert, a.count, a.calculate));
const b = new MyClass('my-ele2');
b.click$.subscribe(() => b.action());
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
<button type="button" id="my-ele1">me1</button>
<br>
<button type="button" id="my-ele2">me2</button>

How can you pass anonymous functions as parameters to existing functions to use later in javascript?

I am trying to create a basic javascript framework that you can pass different things into, including functions for it to execute later. Right now, I'm in a more simple testing phase, but I can't quite get the function calling to work. A piece of my code is here:
[My JS Fiddle][1]http://jsfiddle.net/mp243wm6/
My code has an object that holds different data, and I want to call the method later, but with data that is available at the time of creation. Here is a code snippet of the function that uses the function that is passed to the object:
clickMe : function() {
this.obj.click(function() {
this.func();
});
}
Any suggestions or things I should read are welcome.
The problem is that there're two different contexts:
clickMe : function() {
// here is one
this.obj.click(function() {
// here is another
this.func();
});
}
You can simple pass the function as parameter, like the following:
clickMe : function() {
this.obj.click($.proxy(this.func, this));
}
http://jsfiddle.net/mp243wm6/2/
The problem:
Considering your code in the JSFiddle, you have:
onClick : function() {
this.obj.click(function() {
this.func();
});
},
As noted, you have different contexts going on here.
Consider the snippet this.obj.click(function() { this.func(); }). The first this here is a reference to the framework.events object. The second this here is a reference to whatever will be this when this function get called. In the case of your JSFiddle, when this.func gets called, this is actually the DOM object that represents the <div id="test">TEST</div> node. Since it doesn't have a func function, calling func() on it causes:
Uncaught TypeError: undefined is not a function
You have to understand the following: you have to pass the correct this in which you want the function func to be called.
The solution:
A couple of ways to make it work as you would like:
1. with bind
this.obj.click(this.func.bind(this));
This way, you are telling: "call my this.func function, but make sure that it will be called using the this that I am passing as a parameter". Vanilla JS, no $.proxy stuff.
JSFiddle
2. with a copy of the reference to the actual function
onClick : function() {
var theFunctionReference = this.func;
this.obj.click(function() {
theFunctionReference();
});
},
This way, you will not rely on the value of this outside of the context of the framework.events object.
JSFiddle
The issue is that this is not bound to the correct object. I would suggest you look into Function.bind() because that creates a function with this pointing to the right thing.

Categories

Resources