Why "() => this.tick()" and "this.tick()" are not the same? - javascript

I am looking at this code: https://reactjs.org/docs/state-and-lifecycle.html
I do not understand why I need to use () => this.tick() instead of just this.tick(). The prior calls a function that uses this.tick(), yet when I change () => this.tick() to this.tick(), the code stops working. this.tick() is no longer being called even though it itself is a function. () => this.tick() seems to be just an unnecessary step and yet it is necessary.
I think I am misunderstanding functions as objects.
Thank you

If you pass () => this.tick() then you are passing a function.
If you pass this.tick() then you are passing the value returned by the function.
setInterval(func, delay[, param1, param2, ...]) expects a function as first parameter.

() => this.tick() is a function that when executed will call this.tick() with the appropriate context. If you didn't want to use arrow syntax, you would need to bind the this context similar to this.tick.bind(this);

The arrow function used there is needed to bind the this context, so that it can use this in it's own function.
If you would have only setTimeout( this.tick, 1000 ), it would rightfully call the function on the class, however, that function wouldn't have a this scope...
...unless you bind the this scope in the constructor, or as part of the setTimeout call itself
To do it in the constructor you would have something like
class Clock extends Component {
constructor() {
super();
this.tick = this.tick.bind(this);
}
// other functions
tick() {
this.setState(/*.. state content ..*/):
}
}
another option would be the
setTimeout( this.tick.bind( this ), 1000 );
but that would do the same as what the arrow function is doing for you anyhow, so why not use the arrow function instead.
Another option would be the experimental class properties where you would still have an arrow function, but as this is not the most optimal solution when it comes to testing, I will not directly discuss that one

Firstly, setInterval takes a function as a parameter. Hence unless this.tick returns a function, passing this.tick() to setInterval is incorrect.
setInterval defers the callback method in the event loop. And hence at the time of its execution, the current reference to this will have been lost, as its scope is within its parent function which would have completed its execution. So this would be pointing to window or undefined ins strict mode.
To make it work, you need to preserve the reference, for which we create a closure by creating a new function () => this.tick. Now the reference will be preserved even after parent funtion completes its execution.

You need to give the function a callback to be invoked. A callback is a function that is to be executed after another function has finished. For example using a setTimeout is a built-in function, you give tick a callback because once setTimeout is finished you would like tick to be invoked.
Hope this helps!

Related

Javascript callback vs inline initialing 'callback'

I am new to javascript, I have gone through tutorials about callbacks, but I don't see any that answers this, both method below offers the same results, the only difference I see is callback allows dynamically passing in a callback function.
Are there other advantages, I am missing?
Thank you.
Callback
function logOne(callback) {
setTimeout(() => {
console.log("one");
callback();
}, 1000);
}
function logTwo() {
console.log("two");
}
logOne(logTwo); // one, two
No Callback
function logOne() {
setTimeout(() => {
console.log("one");
logTwo();
}, 1000);
}
function logTwo() {
console.log("two");
}
logOne(); // one, two
Your first example is more flexible: You can use any callback, not just logTwo.
Both have their uses, it depends on whether you need the flexibility or whether logOne should be specifically tied to logTwo.
Callback of function: If you want to do some operation on some event
Like show time on click of a button. Then you override onclick
function for that button. So whenever (independent on time) that
button is clicked, that application internal framework will call
onclick event and your onclick function will be called.
Normal function : Every function is normal function
Calling a function is when you actually do the function.
Passing a function is when function A needs function B in order to
work. So when you call function A, you pass it function B as an
argument. In this case you are not calling function B, instead you are
providing it to function A so that function A can call it.
Your second example create a tight coupling between logOne and logTwo functions. This way you end up with a logOne function that can't be reused since it only works with one exact function.
By passing a callback, you make your function more flexible and generalized. Now it is able to work with a wide range of other functions as long as they have the same "shape" - same number of arguments in a same order.

Can someone explain this piece of Javascript code?

Sorry for the ambiguous title, I just didn't know what else to put. Im learning JS and in the video the person does this.
When he calls the addListAfterKeyPress method at the bottom, why does the function call work? I thought he would have to put in a argument for the addListAfterKeyPress to take in since it has an event parameter. But in the end the code works perfectly. And also, when can i call a function that takes a parameter without explicitly passing one like how he did it in the picture?
This is a so called callback.
addListAfterKeypress at line 30 is not a call to this function, it is just saying, whenever the event keypress is raised on this input element, call this function.
Who is calling the function is the DOM library, indeed. You just have to pass a pointer to the function to be called.
Even more, the addListAfterKeypress function expects an event parameter, which will be provided to the function by the DOM library.
I think it is a bit more understanding by looking at an annonymous function there.
input.addEventListener('keypress', event => {
// This will be run whenever the input raises an event of type 'keypress'
// Here, the DOM library provides me an event parameter
});
Edit on demand:
Be aware, I am using ES6 just for comfort.
Suppose having this function
const callback = () => {
console.log(`My callback function is being executed`);
};
I will be using setTimeout to mock the HTML events. setTimeout is a function that expects a callback to execute after n milliseconds.The first parameter is the callback itself, the second is the amount of milliseconds, n.
See https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(callback, 500); // After 500ms, function callback will be fired
Here, I am just passing a pointer to the setTimeout function. This pointer must point to a function that will be called by setTimeout.
Let's write our own function that takes a callback as a parameter.
const callback2 = (number) => {
console.log('I received this parameter', number);
};
const callbackWrap = (callback, n) => {
// Here, callback parameter is a function that I can invoke, actually
console.log('The wrapper will execute the function passed as parameter');
callback(n);
};
Now, we can call the wrapper pointing to the new callback (callback2).
callbackWrap(callback2, 3);
callbackWrap(callback2, 4);
Or, we can define our function directly on the parameter list.
That is, we are passing an annonymous function
// p is the parameter of the callback function
callbackWrap(p => {
// Since callbackWrap will call the function parameter
// by passing a single parameter,
// the function I am declaring, expects that parameter
console.log(`Received ${p} inside the annonymous function`);
}, 'Parameter');
So, to summerize a bit, just the same way you can declare a variable (let's say, of type number) and then pass it to a function as a parameter, you can declare a function to pass it the same way.
const normalParameter = 30;
const functionParameter = p => console.log('Another callback', p);
callbackWrap(functionParameter, normalParameter);
// Or maybe passing more complex parameters
const anotherParameter = [1, '2', {3: 4}];
callbackWrap(functionParameter, anotherParameter );
Hope it clarifies a bit.

React binding function

I have seen a lot of reactjs places where a function is called like below
onChange = {this.fileSelected}
whereas I have seen its usage like below as well
onClick={() => this.clearDisplay()}
I want to ask if they both mean the same or is there any difference and what to use when.
If you use First:
onChange = {this.fileSelected}
It will only execute when onChange is called. If you want to bind this function then you have to declare it in the component class constructor like this:
constructor(props) {
super(props);
this.state = {
// your state
};
this.clearDisplay = this.clearDisplay.bind(this);
}
The Second one:
onClick={() => this.clearDisplay()}
This defines an anonymous function but, does not call it. Only when onClick is fired is it called. However, in some cases using an anonymous function can cause performance issues. That anonymous function will be defined on every render - and if you have a component that is re-rendering very often it can hurt the performance of your application. If you are sure that the component will not be rendered often, an anonymous function should be fine for convenience.
onChange={this.fileSelected}
Is preferable because it is able to not cause unnecessary re-renders.
onClick={() => this.clearDisplay()}
When you pass an anonymous function like this it will actually be called on all instances of the class instead of the one that the event was triggered on.
From a high level in may seem like they have the same behavior but if you were to use the second method consistently through a large codebase the performance of your application would suffer.
This article goes more in depth on the issue:
https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36
onChange = {this.fileSelected}
This will direct bind fileSelected function to onChange method. so when onChange method called it will call fileSelected function.
while
onClick={() => this.clearDisplay()}
This will call onClick function in which you are calling clearDisplay function. so when you onClick method called, first anonymous called in which clearDisplay function called. So basically in this method two functions called. in this methos you can do additional calls or other things
e.g.
onClick={() => {
console.log("this function called")
this.clearDisplay();
}

setInterval function without arrow function

I am learning about react components following the documentation https://facebook.github.io/react/docs/state-and-lifecycle.html
Why do we need to use arrow function here:
this.timerID = setInterval(() => this.tick(), 1000);
Why can't I just say (obviously it doesn't work)
this.timerID = setInterval(this.tick(), 1000);
The first argument for setInterval is of type function. If you write this:
this.timerID = setInterval(this.tick(), 1000);
…then you don't pass a function, instead you execute the function this.tick immediately and then pass the value returned by that function call as an argument.
You could write it like this:
this.timerID = setInterval(this.tick, 1000);
If you omit the parentheses, you pass a reference to your this.tick function, which is then executed by setInterval after 1000 milliseconds.
setInterval takes function as first argument, in the second case it is getting a returned value
Change it to
this.timerID = setInterval(this.tick.bind(this), 1000);
or
this.timerID = setInterval(() => this.tick(), 1000);
which is probably what you need when you want to bind the function to the React context.
See this answer on why you need to bind functions in React
If you don't you could have simply written
this.timerID = setInterval(this.tick, 1000);
Why do we need to use arrow function here
Answer is simple :
see the result inside live script example...
class Persons{
scopeOne(){
// your will see the result this will display our current object 'Persons'
setInterval(function(){
console.info(' SCOPE ONEo : '+this);
},3000);
}
scopeTwo(){
setInterval(function(){
console.info(' SCOPE TWO : '+this);
}.bind(this) ,3000);
}
scopeThree(){
setInterval(() => { console.info(' SCOPE THREE : '+this) },3000);
}
}
let p = new Persons();
p.scopeOne();
p.scopeTwo();
p.scopeThree();
in first scope the result is WINDOW OBJECT so we cannot access our current class scope
so in 2nd scope we using scope with bind(this) that helps to bind our current object scope,
and in third which do same as 2nd scope calling the current object....
The simple answer to that is that the tick function needs to be able access the context of its use/ this, which is the Clock component. In other words it needs to be bound to the Clock component so that it works in the context of the Clock component and not the global context which is everything outside of the Clock component.
Functions within React classes are not bound by default and failure to bind the function will return undefined instead of the expected result.
There are several ways to bind the tick function to the Clock component example from the Reactjs website.
Arrow functions can access this which is why they are used in the example. In other words, writing an arrow function implicitly means it binds its contents to the local context (the Clock component in this case). Read more on that in this Medium article
Bind the tick function in the constructor
class Clock extends React.Component{
constructor(props){
super(props);
this.state={date: new Date()}
this.tick=this.tick.bind(this)
}
Bind the tick function in the setInterval method
componentDidMount() {
this.timerID = setInterval(this.tick.bind(this),
1000
);
}
Transform a function called tick into a variable with an anonymous function, so you can pass it as an argument without parentheses.
Taking this code (https://codepen.io/gaearon/pen/amqdNr?editors=0010) as a base, you can update like this:
componentDidMount() {
this.timerID = setInterval(this.tick,1000);
}
tick = () => {
this.setState({
date: new Date()
});
}
Generally speaking, whenever you are going to pass a function as a parameter in js that uses an object variable, you need to BIND it with its object, so you don´t lose this reference. The two ways to do this are: using arrow functions or using bind().
You need to supply a function reference, you are trying to invoke a function, unless that function returns a function reference, your code will not work
It should look like so
this.tick = function() { .... }
this.timerID = setInterval(this.tick, 1000);
If you are not using arrow function then your code should look something like this:
this.timerID = setInterval(function(){ this.tick() }, 1000);
Technically, you should be able to use the second code snippet if this.tick() returns a function.

setTimeout nuances in Node.js

I'm trying to understand how the callback function works inside the setTimeout function. I'm aware the format is: setTimeout(callback, delay) I wrote a little test script to explore this.
test1.js
console.log("Hello")
setTimeout(function () { console.log("Goodbye!") }, 5000)
console.log("Non-blocking")
This works as expected, printing Hello <CRLF> Non-blocking and then 5 seconds later, prints Goodbye!
I then wanted to bring the function outside of the setTimeout like this:
console.log("Hello")
setTimeout(goodbye(), 5000)
console.log("Non-blocking")
function goodbye () {
console.log("Goodbye")
}
but it doesn't work and there isn't a 5 second delay between Non-blocking and Goodbye!, they print straight after each other.
It works if I remove the brackets from the function call in the timeout, like this:
setTimeout(goodbye, 5000)
but this doesn't make sense to me because that's not how you call a function. Futhermore, how would you pass arguments to the function if it looked like this?!
var name = "Adam"
console.log("Hello")
setTimeout(goodbye(name), 5000)
console.log("Non-blocking")
function goodbye (name) {
console.log("Goodbye "+name)
}
My question is really, why doesn't it work when there are parameters in the function, despite the fact the setTimeout is being provided with a valid function with the correct syntax?
By putting the parentheses after your function name, you are effectively calling it, and not passing the function as a callback.
To provide parameters to the function you are calling:
You can pass an anon function. setTimeout(function(){goodbye(name)}, 5000);
Or, you can pass the arguments as a third parameter. setTimeout(goodbye, 5000, name);
Look at this question: How can I pass a parameter to a setTimeout() callback?
No matter where you place it, goodbye(name) executes the function immediately. So you should instead pass the function itself to setTimeout(): setTimeout(goodbye, 5000, name).
When you use it like this:
setTimeout(goodbye(), 5000);
it will first call goodbye to get its return value, then it will call setTimeout using the returned value.
You should call setTimeout with a reference to a callback function, i.e. only specifying the name of the function so that you get its reference instead of calling it:
setTimeout(goodbye, 5000);
To make a function reference when you want to send a parameter to the callback function, you can wrap it in a function expression:
setTimeout(function() { goodbye(name); }, 5000);
You can use parantheses in the call, but then the function should return a function reference to the actual callback function:
setTimeout(createCallback(), 5000);
function createCallback() {
return function() {
console.log("Goodbye");
};
}

Categories