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

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.

Related

Why does a React JSX element event handler not use parentheses similar to a html event handler?

While learning HTML event handlers and then React I've understood that in HTML the event handler value e.g. a function should be followed by parentheses. As I understand it, JSX elements are another way to write html like elements in React but when writing these elements we're supposed to omit the parentheses and I can't understand why? shouldn't they behave the same if they represent HTML like elements?
<button onClick={shoot}>JSX element!</button>
<button onclick="shoot()">HTML element!</button>
The code between { and } in JSX is a JavaScript expression. The value passed to a React onClick handler needs to be a function.
So onClick={foo} is equivalent to addEventListener("click", foo);
But onClick={foo()} is equivalent to addEventListener("click", foo());. The expression foo() would call the foo function and resolve to be its return value. This is fine if foo returns another function, and useless if it doesn't.
The value of an HTML onclick attribute is a string (all attribute values are strings) that gets evaluated as the body of a function.
So onclick="foo()" is (very roughly because intrinsic event attributes also do weird things to scope) equivalent to addEventListener("click", new Function("foo()");
A function which just mentions foo, on the other hand, wouldn't do anything.
function foo() {
console.log("I've been called!");
}
function onClick() {
foo;
}
onClick();
So Lets say we have a function
const shoot = () => { };
this how we execute it
shoot(); // this will execute the function
and now this is how we bind a function to a event, we don't call it like document.addEventListener('click', shoot());, we just pass the reference to the function so, when the event happens the function will get executed.
document.addEventListener('click', shoot); // shoot will execute when click on tghe document
Now This will trigger the shoot() when this element attaching to the dom, because it's shoot(), so we trigger it instantly
<button onclick="shoot()">HTML element!</button>
But This will call when the click happens, Why? we pass the reference to the function, so when the click happens js, can trigger the function
<button onClick={shoot}>JSX element!</button>
A React JSX element event handler doesn't use parenthesis because the event handler is a function and not a function call.
e.g -
import React from 'react'
function FunctionClick() {
function clickHandler(){
console.log("button clicked")
}
return (
<div>
<button onClick={clickHandler}>Click</button>
</div>
)
}
export default FunctionClick
If we add parenthesis after event handler then the console message will already be logged in output without hitting the click button. Scenario becomes worse in class component when event handler changes the state of the component, the component constantly re-renders and might see an infinite no of messages in console.

React: Callback arrow functions vs direct trigger

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.

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 !

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