Chapter 6: Handling Events
1. Event Handling in React – The Basics
In plain HTML/JavaScript, we write event handlers like this:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
<button onclick="handleClick()">Click me</button> <script> function handleClick() { alert("Clicked!"); } </script> |
In React → we do it differently (and much cleaner):
- We use camelCase event names: onClick, onChange, onSubmit, onMouseOver, etc.
- We pass a function reference (not a string)
- React handles event delegation behind the scenes (super efficient)
Golden Rule: Do NOT call the function immediately with () inside the JSX — that runs it instantly!
| Wrong (runs immediately on render) | Correct (runs only on click) |
|---|---|
| <button onClick={handleClick()}> | <button onClick={handleClick}> |
| <button onClick={alert(‘hi’)}> | <button onClick={() => alert(‘hi’)}> |
2. Common Events in React
Here are the most used ones:
| Event Name | Triggered When… | Example Usage |
|---|---|---|
| onClick | User clicks (mouse or tap) | Buttons, cards |
| onChange | Input, select, textarea value changes | Forms, search bars |
| onSubmit | Form is submitted (Enter or button) | Login, signup forms |
| onKeyDown | Key is pressed down | Enter key detection |
| onKeyUp | Key is released | Typing games |
| onMouseEnter | Mouse enters element | Hover effects |
| onMouseLeave | Mouse leaves element | Hover effects |
| onFocus | Element gains focus | Input focus styles |
| onBlur | Element loses focus | Validation on blur |
3. Basic onClick Example
Let’s create a simple Like Button component.
Create src/components/LikeButton.tsx
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import { useState } from 'react'; function LikeButton() { const [likes, setLikes] = useState(0); // Event handler function const handleLike = () => { setLikes(likes + 1); console.log("Someone liked this! ❤️"); }; return ( <div style={{ padding: '20px', textAlign: 'center' }}> <button onClick={handleLike} // ← pass function reference style={{ padding: '12px 24px', fontSize: '18px', backgroundColor: likes > 0 ? '#ff6b6b' : '#eee', color: likes > 0 ? 'white' : 'black', border: 'none', borderRadius: '8px', cursor: 'pointer', transition: 'all 0.2s' }} > ❤️ Like {likes > 0 && `(${likes})`} </button> </div> ); } export default LikeButton; |
Use in App.tsx:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import LikeButton from './components/LikeButton'; function App() { return ( <div style={{ padding: '40px', textAlign: 'center' }}> <h1>Event Handling Chapter</h1> <LikeButton /> <LikeButton /> {/* each has its own independent state! */} </div> ); } |
4. Passing Arguments to Event Handlers
There are 3 clean ways to pass extra data:
Way 1: Arrow function (most common & recommended)
|
0 1 2 3 4 5 6 7 8 |
<button onClick={() => handleLike(postId)}> Like Post </button> |
Way 2: Bind (older style, still works)
|
0 1 2 3 4 5 6 7 8 |
<button onClick={handleLike.bind(null, postId)}> Like Post </button> |
Way 3: Wrapper function (good for complex logic)
|
0 1 2 3 4 5 6 7 8 9 10 11 |
const handleLikeWrapper = () => { handleLike(postId); trackAnalytics(); }; <button onClick={handleLikeWrapper}> |
Realistic Example: Like a specific post
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
function PostCard({ id, title }: { id: number; title: string }) { const [likes, setLikes] = useState(0); const handleLike = (postId: number) => { setLikes(prev => prev + 1); console.log(`Post ${postId} got a like! Total: ${likes + 1}`); }; return ( <div style={{ border: '1px solid #ddd', borderRadius: '12px', padding: '20px', margin: '20px', maxWidth: '400px' }}> <h3>{title}</h3> <button onClick={() => handleLike(id)} // ← passing argument style={{ padding: '10px 20px', background: '#ff6b6b', color: 'white', border: 'none', borderRadius: '8px', cursor: 'pointer' }} > ❤️ Like ({likes}) </button> </div> ); } |
5. onChange – Making Forms Interactive
Let’s build a live search input that shows what you type.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import { useState } from 'react'; function SearchBox() { const [query, setQuery] = useState(''); return ( <div style={{ padding: '40px' }}> <h2>Live Search</h2> <input type="text" value={query} onChange={(e) => setQuery(e.target.value)} // ← updates state on every keystroke placeholder="Type something..." style={{ padding: '12px', fontSize: '18px', width: '300px', borderRadius: '8px', border: '1px solid #ddd' }} /> <p style={{ marginTop: '20px', fontSize: '20px' }}> You typed: <strong>{query || '(nothing yet)'}</strong> </p> {/* Bonus: real-time length counter */} <p>Characters: {query.length}</p> </div> ); } export default SearchBox; |
6. onSubmit – Handling Form Submission
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
function LoginForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // ← prevents page reload! if (!email || !password) { alert("Please fill both fields!"); return; } alert(`Logging in with:\nEmail: ${email}\nPassword: ${password}`); // In real app → send to backend here }; return ( <form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '400px', margin: '40px auto', padding: '30px', border: '1px solid #ddd', borderRadius: '12px' }} > <h2>Login</h2> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required style={{ padding: '12px', fontSize: '16px' }} /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required style={{ padding: '12px', fontSize: '16px' }} /> <button type="submit" style={{ padding: '12px', background: '#646cff', color: 'white', border: 'none', borderRadius: '8px', fontSize: '18px', cursor: 'pointer' }} > Login </button> </form> ); } |
Summary – Chapter 6 Key Takeaways
- Use camelCase event names: onClick, onChange, onSubmit
- Pass function reference → onClick={handleClick} (NOT handleClick())
- Use arrow function to pass arguments → () => handleLike(id)
- e.preventDefault() is crucial for forms to stop page reload
- onChange + value + setState = controlled inputs
- Every component can have its own event handlers and state
Mini Homework
- Create a CounterWithButtons component with:
- +1, +5, +10 buttons
- Reset button
- Show current count
- Bonus: Add a ColorPicker with 3 buttons (Red, Green, Blue) that change the background color of a box using state.
