React: Callback arrow functions vs direct trigger - javascript

I am not exactly sure how to describe it but let's say I have this code <button onClick={() => exampleFunction}>Text</button> and this code <button onClick={exampleFunction}>Text</button>, so what's the difference in both examples working? I noticed that in case of onChange only second example works.
Could anyone clarify it?

In your first example you're not actually invoking exampleFunction. You're providing a function that returns exampleFunction.
This:
() => exampleFunction
is the equivalent of:
function () { // invoked by the underlying component
return exampleFunction; // returned, but never called.
}
To fix it, add the parens:
() => exampleFunction()
In the second form, you're passing exampleFunction directly, which is a function. It gets invoked by the underlying component.

Related

Immediately invoked arrow function as a react prop

I have noticed an interesting issue in my React project. I have solved the issue by following the 1st approach but I wish to know the difference between the following callback approaches while passing as a prop:
1. Arrow function (works fine inside render())
changeImage={ () => this.handleImageUploadModal('OPEN') }
2. Function reference (Uncaught RangeError: Maximum call stack size exceeded)
changeImage={ this.handleImageUploadModal('OPEN') }
The first is a function definition, you tell it to "perform this function on change". The important word is 'definition': You dont excecute it, you define it. It doesn't have the 'start' command:
changeImage={ () => {return this.handleImageUploadModal('OPEN')}() }
// If you want it called instantly, you have to start it: --^^
The second one you should read as a parameter. A more obvious example:
showImage={ this.shouldImageBeShown() }
That function will be called instantly to determine wether or not we should show the image, and returns true/false -> showImage={true}.
If you want to enter the functionname without it being triggered, you can remove the () part of the function so that it doesnt get called, only declared:
changeImage={ this.openImageUploadModal }
changeImage={ this.handleImageUploadModal('OPEN') }
This means "call handleImageUploadModal immediately, and pass its return value into the changeImage prop". I'm guessing handleImageUploadModal calls setState, which means the component will rerender and this process repeats.
changeImage={ () => this.handleImageUploadModal('OPEN') }
This means "create a function with the text () => this.handleImageUploadModal('OPEN') and pass it into the changeImage prop". The newly created function is not called (yet), but can be called whenever the component deems it necessary.

Why do I need to pass an anonymous function into the onClick event?

I've been trying to learn the basics of React. However, I've come across a section in the tutorial that asks me to place an alert() inside of an onClick event as such:
<button className="square" onClick={() => {alert("click");}}>
{this.state.value}
</button>
I don't understand why the arrow function is required - why can't I just have the alert() on its own?
The docs state:
Forgetting () => and writing onClick={alert('click')} is a common mistake, and would fire the alert every time the component re-renders.
Which is correct - I've tried this, and it does continually call alert(). But why? Isn't it supposed to fire onClick, and not on render? What does the anonymous function do that stops this behaviour?
Because if you call a function, then the function runs. (And you get the return value from it)
const onClick = alert("hello");
console.log(onClick);
If you define a function (X) that calls a function (Y), then it doesn't call Y until you call X.
const onClick = () => alert("hello");
console.log(onClick);
Basically there is differences between calling (Invoking) a function alert() and Defining (Expressing) a function () => {alert()}
When the code runs, i.e when react renders the component, any function call would run that function and that's why we can use IIFE (function() { } )() to inject functions to window object at runtime.
However, handling events with inline function call (like onclick={()=>{alert()}}) is not recommended because every time that event triggered, a new instance of that function would be created and it may slow down your app,
Instead you can DEFINE a function for handling events and just call it when that specific event triggered:
// Bad
render() {
return <button onclick={() => {this.setState({btnClicked: true})}}> Click! </button>
}
// Good
render() {
const handleClick = () => {
this.setState({btnClicked: true})
}
return <button onclick={handleClick}> Click! </button>
}
Because you need a function that gets called only in the instant that the button is clicked. If you pass alert('click') then the parser will find a function call and execute it instantly when it is going over that file.

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 !

What is the difference between onClick={onRouteChange('home')} and onClick={ () => onRouteChange('home')}?

onClick={onRouteChange('home')}
onClick={ () => onRouteChange('home')}
from the tutorials I've been watching, it says that the first one will be called when it's rendered while the latter will run whenever onClick happens. I quite don't get it.
Events such as onClick, onBlur, etc must be assigned a function (aka callback). That function will be exectured when the related event is fired. In other words, it must be assigned a function which contains the code to be executed when that event occurs.
This means that:
onClick={onRouteChange('home')}
this assigns the return value of onRouteChange('home') to the click event. If that function returns a function, then you're all good. But I am guessing this isn't the case.
onClick={() => onRouteChange('home')}
This assigns an anonymous function (which is the () => part), which when run, invokes the onRouteChange function. This is probably what you want.
So if your function is something like:
onRouteChange(path) {
this.props.history.push(path);
}
Then you want the last solution.
However, if it is more like:
onRouteChange(path) {
return () => {
this.props.history.push(path);
};
}
then the first solution would work.

Stop onClick functions executing on mount without using () => function(someVal)

I'm getting really annoyed by this behaviour that occurs onClick:
If I have:
<button onClick={ this.myFunc(myVal) }></button>
This fires as soon as component mounts not when button is clicked, hence I need to do the following in order to fix it:
<button onClick={ () => this.myFunc(myVal) }></button>
But I believe this is not the correct way to achieve this? Also what if I want to actually pass this.myFunc(myVal) down to another component? It would not work.
When you say
<button onClick={ this.myFunc(myVal) }></button>
You are telling React that you want the returned value from executing this.myFunc(myVal) to be assigned to the onClick handler. Instead you, probably want to give it the function with the parameter set as default:
<button onClick={ this.myFunc.bind(this, myVal) }></button>
This binds myVal as the first argument to this.myFunc and ensures that the context is also bound properly as well. Keep in mind that this causes the event parameter to be passed in as the second parameter to the function.
you are calling the function while doing like below, thats why your method gets called immediately after mounting
<button onClick={ this.myFunc(myVal) }></button>
you have to just assign the function like below
<button onClick={ this.myFunc }></button>
if you want to pass variables to that method, add that variable to state and access that from ther.
The onClick attribute expects a function as a parameter.
That is why the second setup IS correct, and 1st one is not (unless myFunc returns a function)..
The following are functions:
(event) => myFunc(myVal, event) // anonymous function, which calls myFunc IF executed
myFunc.bind(this, myVal) // myFunc without parentheses, with parameters - including event - bound
The following is not a function
myFunc(myVal) // == THE RESULT of the function, so == whatever myFunc returns
In an example:
// myFunc is a function that calls another function
// returns length of whatever is passed in
myFunc(val) {
otherFunc()
return (val.length)
}
// here: myFunc is defined, but it has never executed: otherFunc was not called
let myVal = [1,2]
let callback = () => myFunc(myVal)
// here myFunc is still NOT called, neither is otherFunc
// callback is now defined as a (anonymous) function, which, whenever called
// will execute the function myFunc, by passing in the value of myVal
let a = myFunc(myVal)
// here: myFunc WILL be called, so also otherFunc
// at this point a == 2 (the length of the array myVal)
let b = callback()
// here, callback function is executed, and so also myFunc
// at this point b == 2

Categories

Resources