In the React tutorial, it says
Doing
onClick={alert('click')}
would alert immediately instead of when the button is clicked.
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
However, I cannot understand why that would be... can anyone clarify this for me please? Why can't you pass a function invocation as a handler?
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 ofalert
(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:
Imagine if we invoked the function as
on('click', alert('test'))
, thenalert('test')
would be evaluated and the return value would be passed as the handler, which is undefined. Then you would be trying to callundefined()
, not good. Thus, you must pass a function reference, a reference to a callable function.When you do
onClick={alert("click")}
that's going to call thealert
function and assign the returned value (undefined
) to theonClick
property. So, what React sees isonClick={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, notundefined
.Therefore, you have to do:
onClick={myFunction}
wheremyFunction
can be() => alert("...")
as you mentioned, or you can usebind
to create a similar function:bind
will return a new function which will internally call thealert
function with the"click"
argument.A similar case is when you do
setTimeout(() => alert("after 1 second"), 1000)
.setTimeout
expects a function. If you dosetTimeout(alert("..."), 1000)
, thealert
will be called, indeed, but thesetTimeout
will receive as first argumentundefined
(that's whatalert
returns).Instead, if you have a function which returns a function, that will work:
You can use it in the same way for the
onClick
thingy: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):