๐ก Key Takeaways
๐ฑ Event Handling: Use camelCase events (onClick, onChange) with synthetic events.
โก Controlled Components: Tie input values to React state for sync and validation.
๐งญ Event Delegation: Attach listeners to parent elements for performance with lists.
โณ Optimization: Use useCallback, debounce handlers, and cleanup with useEffect.
๐น Accessibility: Manage focus, keyboard events, and ARIA roles for inclusive UI.
๐ฑ Basic Event Handling
- Event names are camelCase (
onClick,onChange) - Handlers receive synthetic events
- Pass parameters via arrow function wrappers
function handleClick(name) {
console.log('Hello', name);
}
<button onClick={() => handleClick('React')}>Click me</button>
๐ Common Event Types
- Mouse:
onClick,onMouseEnter,onMouseLeave - Keyboard:
onKeyDown,onKeyUp,onKeyPress - Form:
onChange,onSubmit,onFocus,onBlur - Clipboard/Touch:
onCopy,onPaste,onTouchStart
<input
onChange={(e) => console.log('Changed:', e.target.value)}
onFocus={() => console.log('Focused')}
/>
โก Synthetic Events
- Normalize browser differences
- Use
event.preventDefault()andevent.stopPropagation() - Access target with
event.target/event.currentTarget - React pools events, read data before async use
function handleClick(event) {
event.preventDefault();
console.log(event.type, event.target.tagName);
}
๐ Controlled Components
- Input value tied to React state
- Handle changes with
onChange - Ideal for validation and dynamic forms
- Keeps UI synced with data
function ControlledInput() {
const [value, setValue] = useState('');
return <input value={value} onChange={e => setValue(e.target.value)} />;
}
๐งญ Event Delegation
- Attach listener to a parent element
- Detect child using
event.target - Reduces overhead for large lists
- Useful for menus or dynamic items
function List() {
const handleClick = e => {
if (e.target.tagName === 'LI') console.log('Clicked:', e.target.textContent);
};
return (
<ul onClick={handleClick}>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
);
}
๐ง Custom Hooks for Events
- Reusable listeners with hooks
- Auto-cleanup via
useEffect - Ideal for global events (
resize,keydown) - Separates logic from UI
function useEventListener(type, handler, target = window) {
useEffect(() => {
target.addEventListener(type, handler);
return () => target.removeEventListener(type, handler);
}, [type, handler, target]);
}
โ๏ธ Optimizing Event Handlers
- Memoize handlers with
useCallback - Avoid unnecessary re-renders
- Use delegation for dynamic lists
- Avoid inline functions in large components
const handleClick = useCallback(id => console.log('Clicked:', id), []);
โณ Debounced Handlers
- Debounce rapid-fire events
- Useful for search inputs or resize
- Implement with timeout + cleanup
- Improves performance
function useDebounce(fn, delay) {
const ref = useRef();
return useCallback((...args) => {
clearTimeout(ref.current);
ref.current = setTimeout(() => fn(...args), delay);
}, [fn, delay]);
}
๐งพ Form Handling
- Intercept submissions with
onSubmit - Prevent default reload with
event.preventDefault() - Extract data via
FormDataor controlled inputs - Validate before submission
function ContactForm() {
const handleSubmit = e => {
e.preventDefault();
const data = Object.fromEntries(new FormData(e.target));
console.log(data);
};
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" />
<button>Submit</button>
</form>
);
}
๐น Keyboard Events
- Add shortcuts via
keydown - Detect combos like
Ctrl + S - Lifecycle management with
useEffect - Cleanup on unmount
useEffect(() => {
const handleKeyDown = e => e.key === 'Escape' && console.log('Cancel');
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
๐งฉ Accessibility & Focus
- Support keyboard users (
onKeyDown) - Use
tabIndex&rolefor focusable elements - Manage focus with
useRef - Provide visual focus states
function Focusable() {
const inputRef = useRef();
return (
<div onKeyDown={e => e.key === 'Enter' && inputRef.current.focus()}>
<button>Focus input</button>
<input ref={inputRef} />
</div>
);
}
โ Best Practices
- Memoize handlers (
useCallback) - Use delegation for list-heavy UIs
- Clean up listeners in
useEffect - Avoid inline handlers in loops
useEffect(() => {
const onResize = () => console.log('resized');
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
}, []);