In the React tutorial, it says
Doing
onClick={alert(\'click\')}
would alert immediately instead of when the button is clicked.
When you do onClick={alert("click")}
that's going to call the alert
function and assign the returned value (undefined
) to the onClick
property. So, what React sees is onClick={undefined}
and says: well, that's not a function, why would I add such a handler?
What you want to pass to onClick
is a function, not undefined
.
Therefore, you have to do: onClick={myFunction}
where myFunction
can be () => alert("...")
as you mentioned, or you can use bind
to create a similar function:
onClick={alert.bind(window, "click")}
bind
will return a new function which will internally call the alert
function with the "click"
argument.
A similar case is when you do setTimeout(() => alert("after 1 second"), 1000)
. setTimeout
expects a function. If you do setTimeout(alert("..."), 1000)
, the alert
will be called, indeed, but the setTimeout
will receive as first argument undefined
(that's what alert
returns).
Instead, if you have a function which returns a function, that will work:
// This will be called first and will return a function
const sayHelloTo = name => {
// This will be the function passed to `setTimeout`
return () => alert(`Hello ${name}`);
};
setTimeout(sayHelloTo("Alice"), 1000);
You can use it in the same way for the onClick
thingy:
onClick={sayHelloTo("Alice")}
This is a very tiny example about what happens in the background (it's just a proof of concept, I'm sure what it actually happens is way better than this):
const elm = {
onClick: null,
// The click method can be invoked manually
// using `elm.click()` or is natively invoked by the browser
click () {
if (typeof this.onClick === "function") {
this.onClick();
}
}
};
// If you do:
elm.onClick = alert("click"); // this calls the alert, and returns undefined
elm.onClick === undefined // true
// But when doing:
elm.onClick = () => alert("click");
typeof elm.onClick // "function"
elm.click(); // this will call the alert
When you have an event handler it must be a function reference, not a function invocation. This is because internally when the handler is executed, the handler is first evaluated before it can be called. With inline JSX expressions such as when passing an event handler prop, the expression is evaluated when the component is declared, before the handler is called.
Thus, if you pass in an invocation such as alert('click')
, it will alert as it is being evaluated. When the event is triggered and the handler is called, it will then attempt to call the return value of alert
(which is undefined) -- not good. Instead, you need a function reference, which when evaluated gives you a callable function which is then called as the handler.
Take this pseudocode for an example:
function on(event, handler) {
//some event listener function that runs the handler when event happens
//then we call handler when the event happens:
handler();
}
Imagine if we invoked the function as on('click', alert('test'))
, then alert('test')
would be evaluated and the return value would be passed as the handler, which is undefined. Then you would be trying to call undefined()
, not good. Thus, you must pass a function reference, a reference to a callable function.