Event handling in React is similar to handling events in the DOM, but with a few key differences. React events are named using camelCase (onClick instead of onclick), and you pass a function as the event handler rather than a string. React uses its own synthetic event system to ensure cross-browser compatibility.
// Basic event handling
function ClickButton() {
const handleClick = () => {
alert('Button clicked!');
};
return <button onClick={handleClick}>Click Me</button>;
}
// Multiple event handlers
function InputExample() {
const [value, setValue] = useState('');
const handleChange = (e) => setValue(e.target.value);
const handleFocus = () => console.log('Focused');
const handleKeyDown = (e) => {
if (e.key === 'Enter') {
alert(`Submitted: ${value}`);
}
};
return (
<input
type="text"
value={value}
onChange={handleChange}
onFocus={handleFocus}
onKeyDown={handleKeyDown}
/>
);
}
React wraps native browser events into a SyntheticEvent object that provides a consistent interface across all browsers. The SyntheticEvent has the same properties as native events, including bubbles, cancelable, currentTarget, defaultPrevented, eventPhase, isTrusted, nativeEvent, preventDefault(), stopPropagation(), target, timeStamp, and type.
e.persist() to remove the event from the pool.
// Synthetic event object
function Form() {
const handleSubmit = (e) => {
e.preventDefault(); // Prevent page reload
console.log('Form submitted');
console.log('Target:', e.target);
console.log('Type:', e.type);
};
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
When you need to pass additional arguments to an event handler, you can use an arrow function or the bind method. Arrow functions are the more common and readable approach in modern React.
// Using arrow function (recommended)
function ItemList({ items }) {
const handleItemClick = (id, name) => {
console.log(`Clicked item ${id}: ${name}`);
};
return (
<ul>
{items.map(item => (
<li key={item.id} onClick={() => handleItemClick(item.id, item.name)}>
{item.name}
</li>
))}
</ul>
);
}
function ClickCounter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Clicks: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
function ToggleButton() {
const [isOn, setIsOn] = useState(false);
return (
<button
onClick={() => setIsOn(prev => !prev)}
style={{ background: isOn ? '#22c55e' : '#ef4444' }}
>
{isOn ? 'ON' : 'OFF'}
</button>
);
}
function SignupForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: '',
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form data:', formData);
};
return (
<form onSubmit={handleSubmit}>
<input name="username" value={formData.username} onChange={handleChange} placeholder="Username" />
<input name="email" type="email" value={formData.email} onChange={handleChange} placeholder="Email" />
<input name="password" type="password" value={formData.password} onChange={handleChange} placeholder="Password" />
<button type="submit">Sign Up</button>
</form>
);
}
A common pattern in React is to create components that accept event handlers as props. This allows the parent component to control what happens when events occur, making the child component reusable in different contexts.
function ActionButton({ label, onAction, disabled }) {
return (
<button onClick={onAction} disabled={disabled}>
{label}
</button>
);
}
// Usage
<ActionButton label="Save" onAction={handleSave} disabled={isSaving} />
<ActionButton label="Delete" onAction={handleDelete} disabled={false} />
Create a ColorPicker component that displays three buttons (Red, Green, Blue). When a button is clicked, the background color of a preview box changes to the corresponding color. Use the onClick event handler and pass arguments to identify which color was clicked. Also add a reset button that changes the background back to white.