Handling Events
Responding to user interactions in React
Event Handling in React
React events are similar to DOM events, but with a few key differences. They use camelCase naming (onClick instead of onclick) and you pass functions as event handlers, not strings.
React vs DOM Events
HTML/DOM
<button onclick="handleClick()">
React
<button onClick={handleClick}>
Basic Event Handling
function Button() {
// Define the event handler function
const handleClick = () => {
alert('Button was clicked!');
};
// Pass the function reference (not a function call!)
return <button onClick={handleClick}>Click Me</button>;
}
// Inline handler (for simple cases)
function InlineExample() {
return (
<button onClick={() => alert('Clicked!')}>
Click Me
</button>
);
}
⚠️ Common Mistake
Pass the function, don't call it: onClick={handleClick} ✓
Not: onClick={handleClick()} ✗ (this calls it immediately!)
The Event Object
Event handlers receive a synthetic event object with properties similar to native DOM events:
function Form() {
const handleSubmit = (event) => {
event.preventDefault(); // Prevent form submission
console.log('Form submitted!');
};
const handleChange = (event) => {
console.log('Input value:', event.target.value);
console.log('Input name:', event.target.name);
};
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
console.log('Enter pressed!');
}
console.log('Key:', event.key);
console.log('Ctrl held:', event.ctrlKey);
};
return (
<form onSubmit={handleSubmit}>
<input
name="email"
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
<button type="submit">Submit</button>
</form>
);
}
Common Events
| Category | Events |
|---|---|
| Mouse | onClick, onDoubleClick, onMouseEnter, onMouseLeave, onMouseMove |
| Keyboard | onKeyDown, onKeyUp, onKeyPress |
| Form | onChange, onSubmit, onFocus, onBlur |
| Touch | onTouchStart, onTouchMove, onTouchEnd |
| Scroll | onScroll |
| Clipboard | onCopy, onCut, onPaste |
Passing Arguments to Event Handlers
function ItemList() {
const items = ['Apple', 'Banana', 'Cherry'];
// Method 1: Arrow function wrapper
const handleDelete = (itemName) => {
console.log('Deleting:', itemName);
};
// Method 2: With event object
const handleClick = (id, event) => {
console.log('Clicked item:', id);
console.log('Event:', event);
};
return (
<ul>
{items.map((item, index) => (
<li key={item}>
{item}
{/* Arrow function to pass argument */}
<button onClick={() => handleDelete(item)}>
Delete
</button>
{/* Passing both id and event */}
<button onClick={(e) => handleClick(index, e)}>
Click
</button>
</li>
))}
</ul>
);
}
Events with State
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(prev => prev + 1);
const decrement = () => setCount(prev => prev - 1);
const reset = () => setCount(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
<button onClick={reset}>Reset</button>
</div>
);
}
function ToggleSwitch() {
const [isOn, setIsOn] = useState(false);
const toggle = () => setIsOn(prev => !prev);
return (
<button
onClick={toggle}
style={{ background: isOn ? 'green' : 'gray' }}
>
{isOn ? 'ON' : 'OFF'}
</button>
);
}
Event Handler Naming Conventions
// Convention: handle + Event/Action
function MyComponent() {
// For the handler function
const handleClick = () => { };
const handleSubmit = () => { };
const handleUserDelete = () => { };
const handleInputChange = () => { };
// For props that accept handlers
// Convention: on + Event/Action
return (
<ChildComponent
onClick={handleClick}
onSubmit={handleSubmit}
onUserDelete={handleUserDelete}
/>
);
}
// Child component receives with "on" prefix
function ChildComponent({ onClick, onSubmit, onUserDelete }) {
return (
<button onClick={onClick}>Click</button>
);
}
Preventing Default Behavior
function Form() {
// Prevent form submission reload
const handleSubmit = (e) => {
e.preventDefault();
// Handle form data...
};
return <form onSubmit={handleSubmit}>...</form>;
}
function Link() {
// Prevent link navigation
const handleClick = (e) => {
e.preventDefault();
console.log('Link clicked, but navigation prevented');
};
return <a href="/page" onClick={handleClick}>Click Me</a>;
}
Event Propagation
function Parent() {
const handleParentClick = () => {
console.log('Parent clicked');
};
const handleChildClick = (e) => {
e.stopPropagation(); // Stop event from bubbling up
console.log('Child clicked');
};
return (
<div onClick={handleParentClick} style={{ padding: '20px', background: '#eee' }}>
Parent
<button onClick={handleChildClick}>
Child (won't trigger parent)
</button>
</div>
);
}
// Capture phase (rarely used)
function CaptureExample() {
return (
<div onClickCapture={() => console.log('Captured!')}>
<button onClick={() => console.log('Clicked!')}>
Button
</button>
</div>
);
}
Hover and Focus Events
function InteractiveCard() {
const [isHovered, setIsHovered] = useState(false);
const [isFocused, setIsFocused] = useState(false);
return (
<div
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
style={{
background: isHovered ? '#f0f0f0' : 'white',
transform: isHovered ? 'scale(1.02)' : 'scale(1)'
}}
>
<input
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
style={{
borderColor: isFocused ? 'blue' : 'gray'
}}
/>
</div>
);
}
🎯 Event Handling Best Practices
- ✓ Use camelCase for event names (onClick, onChange)
- ✓ Pass functions, don't call them
- ✓ Use meaningful handler names (handleClick, handleSubmit)
- ✓ Extract complex handlers into named functions
- ✓ Use e.preventDefault() for forms and links when needed
- ✓ Use e.stopPropagation() to prevent event bubbling
- ✓ Keep handlers close to where they're used