Skip to main content

Command Palette

Search for a command to run...

React: Function References vs Function Calls

Updated
4 min read

In React code, you may see the following ways of calling functions in jsx elements:

onClick={handleClick}

onClick={() => handleClick()}

Understanding the difference and when to use which pattern is a common point of confusion. Let’s unpack what’s really going on, and what React is doing with the function you give it.

Function Reference vs Function Call

JavaScript has first-class functions, meaning they can be called with () or passed around as variables (without ()). Let’s illustrate this with a simple function:

function sayHi() {
   return "hi";
}

sayHi(); // "hi"

// or we can pass a reference to this function into another function:
function greet(fn, name) {
  console.log(fn() + " " + name);
}

greet(sayHi, "Joe"); // "hi Joe"

In the greet function, we’ve passed a reference (without parentheses) to the sayHi function. This sayHi function is then called (with parentheses) when the greet function is invoked. The key idea is:

  • sayHi → “Here’s the function.”

  • sayHi() → “Run the function now.”

What React does with onClick

React expects a function reference, not a function call. For example:

<button onClick={sayHi}>Click</button>

React will store the reference to the sayHi function so that later, when the button is clicked, it will run sayHi(event). This is the normal, intended way to tell React to run a function when the button is clicked.

If instead you wrote:

<button onClick={sayHi()}>Click</button>

you would see the sayHi function run immediately when rendered instead of waiting for the click.

Arrow functions

It’s also common to use arrow functions in React event handlers. Let’s illustrate this example using the greet function from earlier:

function greet(name) {
  alert(`Hello, ${name}!`);
}

function GreetingExample() {
  const [name, setName] = useState("");

  return (
    <div>
      <input
        type="text"
        value={name}
        placeholder="Enter your name"
        onChange={(e) => setName(e.target.value)}
      />
      <button onClick={() => greet(name)}>Click</button>
    </div>
  );
}

This function needs to pass an argument, name. But we can’t write it like this:

<button onClick={greet(name)}>Click</button>

because that would call greet(name) immediately during render, not when the user clicks.
The arrow function solves this by giving React a function reference: a small wrapper function that React can call later when the click actually happens. In this pattern, the arrow function creates a new function each render, but that’s perfectly fine for most cases. Here’s how that happens step by step:

  1. React renders the button and stores the arrow function as the click handler.

  2. When the button is clicked, React runs the arrow function.

  3. The arrow function then calls greet(name) with the latest name value.

Pop quiz moment — what would happen if you tried this:

<button onClick={() => sayHi}>Click</button>

If you thought “nothing,” you are correct! Nothing would happen in this example because the arrow function receives a reference to sayHi, but does NOT invoke it!

Analogy

Think of this like giving React your phone number.

  • onClick={fn} → You give React your number. React dials it later.

  • onClick={fn()} → You dial the phone number right now, and give React the result of the call.

  • onClick={() => fn} → You give React a note that says “here’s the number" — but the number is never dialed, and React never makes the call.

When to use which

When to useExampleWhy
You don’t need argumentsonClick={handleClick}Simpler and avoids creating a new function on each render
You need arguments or extra logiconClick={() => handleClick(id)}Lets you call your function with arguments when clicked
❌ Don’t do thisonClick={handleClick()}Calls immediately during render
❌ Or thisonClick={() => handleClick}Returns a function, doesn’t call it

Wrapping up

React doesn’t magically call functions — it simply calls whatever function reference you hand it when an event occurs. Understanding that difference between a function reference (fn) and a function call (fn()) explains nearly every “why doesn’t my onClick work?” moment.

When in doubt:

  • Pass a function reference when you just need to call it later.

  • Use an arrow function when you need to pass arguments or do extra work.

  • Never call the function directly inside JSX unless you explicitly want it to run during render (rare!).