In React, to pass parameters to an event handler, you must wrap the function call so that it is not executed immediately during the component's render phase.
Primary Methods to Pass Parameters
- Arrow Function Wrapper: The most common approach is to use an inline arrow function in the JSX attribute. This creates a new function that calls your handler with the specific arguments when the event occurs.
- Function.bind(): You can use the method to pre-configure a function with specific arguments. The first argument to is the context (usually in functional components or in class components), followed by the parameters you want to pass.
- Currying (High-Order Function): Define a function that returns another function. This is useful for passing parameters while keeping the JSX cleaner.
Handling the Event Object
If you need both a custom parameter and the React SyntheticEvent object (e.g., to call ), you must pass the event explicitly when using an arrow function.
- Arrow Function:
- Bind: (The event object is automatically passed as the last argument)
Performance Considerations
Creating functions inline (using arrow functions or ) generates a
new function instance on every render. While usually fine for small applications, for performance-critical components (like large lists), consider using the
useCallback hook from React.dev to memoize the handler.
How to use useCallback hook to pass parameters
To use the useCallback hook with a parameter, you define the parameter in the function signature within the hook. This caches the function definition, ensuring that the same function instance is used between re-renders unless its dependencies change.
Implementation with an ID Parameter
In this pattern, the useCallback hook defines how to handle the ID, while the actual ID is passed during the execution of that memoized function.
import { useCallback } from 'react';
const MyComponent = ({ items }) => {
// 1. Define the memoized handler with a parameter
const handleItemClick = useCallback((id) => {
console.log(`Clicked item with ID: ${id}`);
}, []); // Empty dependency array means this function reference never changes
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{/* 2. Pass the parameter when the event occurs */}
<button onClick={() => handleItemClick(item.id)}>
Click {item.name}
</button>
</li>
))}
</ul>
);
};
Key Rules for useCallback
- Parameter Location: Parameters are defined in the function passed to
useCallback. They are not passed into the dependency array unless the logic inside the function relies on an external value that changes. - Dependency Array: Only include reactive values (props, state, or variables) that the function uses internally. If you don't use any external variables, use an empty array
[]. - Wrapper Still Required: In your JSX, you still need an inline arrow function (e.g.,
() => handleItemClick(id)) to actually call your memoized function with the specific ID.
When is this actually useful?
Using useCallback with parameters is most effective when:
- Passing to
React.memo Children: If you pass this handler to a child component wrapped in React.memo, a stable function reference prevents the child from re-rendering unnecessarily. - Use in
useEffect: If another useEffect or hook depends on your handler, memoizing it prevents that effect from running on every render.