3

Learning React via a tutorial and I don't understand why I have to create a new function to pass to a JSX onClick and can't just use the one returned from a React useState call.

The below works as it calls handleButtonClick on the button click, but it does not work if I just pass the setMessage function call with a string instead.

Works:

function App() {
  const [message, setMessage] = React.useState('Javascript is so cool');

  function handleButtonClick() {
    setMessage('This is a new message');
  }

  return (
    <div>
      <h1>{message}</h1>
      <button onClick={handleButtonClick}>Update The Message!</button>
    </div>
  );
}

Does Not Work:

function App() {
  //Javascript goes here
  const [message, setMessage] = React.useState('Javascript is so cool');

  function handleButtonClick() {
    setMessage('This is a new message');
  }

  return (
    <div>
      <h1>{message}</h1>
      <button onClick={setMessage('Boom')}>Update The Message!</button>
    </div>
  );

I see that: <button onClick={() => setMessage('Boom')}>Update The Message!</button> works, but I don't get why it has to be setup like this and I can't just use the setMessage call in the same way I use the handleButtonClick call.

norbitrial
  • 14,716
  • 7
  • 32
  • 59
Columbus
  • 133
  • 1
  • 11
  • 1
    They both refer to a function rather than invoking it. Onclick wants to know "Which functions should I call?" So you pass the function, not its invocation. – jmargolisvt Jan 02 '20 at 18:00

4 Answers4

5

That's happened because when you put the function with parenthesis you call the function and if you only put the function without the parenthesis you pass the "pointer".

An example:

// log function
function logTheType(param) {
    console.log(typeof param);
}

// sum function
function sum(a, b) {
    return a + b;
}

// sum is a function
logTheType(sum);
// res: function

// you are calling sum and send the return to the logTheType
logTheType(sum(1, 5));
// res: number

// you pass an anonymous function
logTheType(() => sum(1, 5));
// res: function
jtwalters
  • 1,024
  • 7
  • 25
2

Once React renders the HTML part then from onClick={setMessage('Boom')} will be evaluated in the same time. So setMessage function will return undefined which will be your onClick callback.

To make it work, you need to pass an anonymous function as you mentioned just like the following:

onClick={() => setMessage('Boom')}

In this way you are attaching an event to onClick and setMessage will be called once you click on the button and won't be executed immediately.

From Arrow function expressions' documentation:

An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords.

I hope this helps!

norbitrial
  • 14,716
  • 7
  • 32
  • 59
0

For onClick you need to provide the callback function.

onClick={setMessage('Boom')} // here on render setMessage will be executed.

onClick={() => setMessage('Boom')} // here only click event setMessage will be executed
Siva K V
  • 10,561
  • 2
  • 16
  • 29
0

In not working code you are executing setMessage immidiately, you should change it to be an arrow function.

If you write this onClick={setMessage('Boom')}, then you are executing that function right at render, because onClick needs a function and you are passing function (setMessage), but also executing it with ().

So if you don't need parameters, you can pass setMessage without (), because you need to pass only reference to a function.

In your case out need an arrow function, because you need an argument

Dominik Matis
  • 2,086
  • 10
  • 15