In React, event handlers often need extra information such as IDs, names, or indexes. You can safely pass arguments using arrow functions or bind() without accidentally calling the function during render.
A common pitfall is calling the handler directly inside JSX (for example, onClick={myFunc(5)}), which makes it run immediately instead of waiting for the actual event.
bind() or arrow functions to pass parameters.onClick={handleClick(5)}).bind() in most cases.The most common and clean way to pass arguments in React function components is to wrap the handler in an arrow function. This ensures the handler is only called when the event occurs.
// Functional component: pass a name argument to the click handler
function GreetUser() {
const greet = (name) => alert(`Hello, ${name}!`);
return (
<div>
<button className="btn btn-primary me-2" onClick={() => greet("Ananya")}>
Greet Ananya
</button>
<button className="btn btn-success" onClick={() => greet("Rahul")}>
Greet Rahul
</button>
</div>
);
}
Here, onClick={() => greet("Ananya")} creates a small arrow function that calls greet("Ananya") only when the user actually clicks the button.
In class components, you can use either bind() or arrow functions to pass arguments to your event handlers.
bind()
// Class component: use bind() to pre-fill the name argument
class Welcome extends React.Component {
handleClick(name) {
alert(`Welcome, ${name}!`);
}
render() {
return (
<div>
<button
className="btn btn-warning"
onClick={this.handleClick.bind(this, "Ananya")}
>
Say Hello
</button>
</div>
);
}
}
// Class component: pass argument via an arrow function
class WelcomeArrow extends React.Component {
handleClick(name) {
alert(`Welcome, ${name}!`);
}
render() {
return (
<button
className="btn btn-secondary"
onClick={() => this.handleClick("Rahul")}
>
Greet Rahul
</button>
);
}
}
Both approaches work. Arrow functions in JSX are usually easier to read and avoid rebinding inside render(), especially when combined with hooks and functional components.
You can pass both a custom argument and the event object to the same handler. React automatically passes the event object as the last parameter.
// Pass both a custom ID and the event object to the handler
function HandleBoth() {
const handleClick = (id, e) => {
alert(`Item ID: ${id}`);
console.log("Event type:", e.type);
};
return (
<button
className="btn btn-outline-primary"
onClick={(e) => handleClick(101, e)}
>
Show ID
</button>
);
}
Notice how the event object e is passed as the second argument and React automatically provides it when the click happens.
Be careful not to call the handler directly inside JSX. That causes the function to run during render instead of on user interaction.
// Incorrect: the handler is executed immediately during render
<button onClick={handleClick(5)}>Click</button>
This version calls handleClick(5) right away while rendering, so the alert or logic will run even before the user clicks.
// Correct: wrap the handler call inside an arrow function
<button onClick={() => handleClick(5)}>Click</button>
Here, the arrow function is stored as the click handler, and handleClick(5) is only executed when the button is actually clicked.
Imagine rendering the GreetUser component:
Hello, Ananya!Hello, Rahul!HandleBoth example, clicking the button shows an alert with Item ID: 101 and logs the event type (for example, "click") in the console.The key idea: the alert or console log only runs when the event happens, because the handler is wrapped in an arrow function instead of being called directly during render.
useCallback().map(), consider memoized handlers to reduce unnecessary re-renders.bind() mainly for older class-based components.bind() to pass the product ID.console.log() statements in each handler to see when they are re-created or re-run.Goal: Learn to pass custom arguments and event objects to React event handlers in both function and class components, without triggering unwanted renders or executing handlers too early.