Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
234 views
in Technique[技术] by (71.8m points)

javascript - Why do event handlers need to be references and not invocations?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...