This is about React’s Synthetic Event System and naming conventions. Let me explain why React uses onClick instead of click.
React’s Synthetic Event System
React doesn’t use native DOM events directly. Instead, it creates its own Synthetic Events system that wraps around native DOM events.
HTML vs React Comparison:
<!-- Regular HTML -->
<button onclick="myFunction()">Click me</button>
<!-- React JSX -->
<button onClick={myFunction}>Click me</button>
Key Differences:
1. Naming Convention – camelCase vs lowercase:
// ❌ HTML style (lowercase) - doesn't work in React
<button click={addTodo}>Add Todo</button>
<input change={handleChange} />
<form submit={handleSubmit}>
// ✅ React style (camelCase) - correct
<button onClick={addTodo}>Add Todo</button>
<input onChange={handleChange} />
<form onSubmit={handleSubmit}>
2. More Event Examples:
// HTML → React
onclick → onClick
onchange → onChange
onsubmit → onSubmit
onkeydown → onKeyDown
onkeyup → onKeyUp
onmouseenter → onMouseEnter
onmouseleave → onMouseLeave
onfocus → onFocus
onblur → onBlur
❓ Why React Uses Synthetic Events?
1. Cross-Browser Compatibility:
// Without React - you'd need to handle browser differences
function addEventListenerCrossBrowser(element, event, handler) {
if (element.addEventListener) {
element.addEventListener(event, handler); // Modern browsers
} else if (element.attachEvent) {
element.attachEvent('on' + event, handler); // Old IE
}
}
// With React - it handles all browser differences for you
<button onClick={addTodo}>Add Todo</button>
2. Consistent API:
// React events work the same across all browsers
const handleClick = (e) => {
e.preventDefault(); // Always works
e.stopPropagation(); // Always works
console.log(e.target); // Always works
};
3. Performance Optimization:
// React uses event delegation - attaches one listener to document
// and manages all events from there (more efficient)
<div>
<button onClick={handleClick1}>Button 1</button>
<button onClick={handleClick2}>Button 2</button>
<button onClick={handleClick3}>Button 3</button>
{/* React doesn't attach 3 separate listeners */}
</div>
What happens behind the scenes:
When you write:
<button onClick={addTodo}>Add Todo</button>
React internally:
- Wraps the native click event in a SyntheticEvent
- Normalizes the event across different browsers
- Delegates the event handling to the document root
- Calls your
addTodofunction with the synthetic event
Example of React’s event object:
const handleClick = (e) => {
console.log(e.type); // "click"
console.log(e.target); // The button element
console.log(e.currentTarget); // The button element
console.log(e.preventDefault); // Function to prevent default
// React provides the native event if needed
console.log(e.nativeEvent); // Original DOM event
};
💡 Common Mistakes:
❌ Don’t do this:
// Wrong - lowercase (HTML style)
<button onclick={addTodo}>Add Todo</button>
// Wrong - calling the function immediately
<button onClick={addTodo()}>Add Todo</button>
// Wrong - using string (HTML style)
<button onClick="addTodo()">Add Todo</button>
✅ Do this:
// Correct - camelCase and function reference
<button onClick={addTodo}>Add Todo</button>
// Correct - arrow function for parameters
<button onClick={() => deleteTodo(id)}>Delete</button>
// Correct - arrow function for event access
<button onClick={(e) => handleClick(e, id)}>Click</button>
Full Event System Examples:
const MyComponent = () => {
const handleClick = (e) => {
console.log('Button clicked!');
e.preventDefault(); // Prevent default behavior
};
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
console.log('Enter pressed!');
}
};
const handleMouseEnter = () => {
console.log('Mouse entered!');
};
return (
<div>
<button onClick={handleClick}>Click me</button>
<input onKeyPress={handleKeyPress} />
<div onMouseEnter={handleMouseEnter}>Hover me</div>
</div>
);
};
📝 Summary:
React uses onClick (camelCase) instead of click (lowercase) because:
- Consistency – All React props use camelCase
- Synthetic Events – React wraps native events for better cross-browser support
- Performance – React optimizes event handling with event delegation
- Predictability – Same API across all browsers and components
The onClick you use in React is actually more powerful and reliable than the native onclick in HTML!
❓Questions
1. How Event Delegation Improves Performance?
Event delegation is a powerful optimization technique. Let me show you the difference:
Without Event Delegation (Traditional DOM):
// Imagine you have 1000 buttons - traditional approach
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
button.addEventListener('click', handleClick); // 1000 event listeners!
});
With Event Delegation (React’s approach):
// React attaches ONE listener to the document root
document.addEventListener('click', (e) => {
if (e.target.matches('button')) {
handleClick(e); // Only one listener for all buttons!
}
});
Performance Benefits:
Memory Usage:
// Without delegation: 1000 buttons = 1000 event listeners in memory
// With delegation: 1000 buttons = 1 event listener in memory
DOM Manipulation:
// Without delegation: Adding/removing elements requires managing listeners
const newButton = document.createElement('button');
newButton.addEventListener('click', handleClick); // Must remember to add
document.body.appendChild(newButton);
// With delegation: New elements automatically work
const newButton = document.createElement('button');
document.body.appendChild(newButton); // Automatically handles clicks!
Real React Example:
// Even with 1000 todos, React only has ONE click listener
<ul>
{todos.map(todo => (
<li key={todo.id}>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
<button onClick={() => editTodo(todo.id)}>Edit</button>
</li>
))}
</ul>
// React manages all these clicks with ONE delegated listener
2. Event Parameter Naming – why always use ‘e’ for events?
We can absolutely use different names! e is just a convention, not a requirement.
All of these are valid:
// Common conventions
<button onClick={(e) => handleClick(e, id)}>Click</button>
<button onClick={(event) => handleClick(event, id)}>Click</button>
<button onClick={(evt) => handleClick(evt, id)}>Click</button>
// Your custom names
<button onClick={(v) => handleClick(v, id)}>Click</button>
<button onClick={(ev) => handleClick(ev, id)}>Click</button>
<button onClick={(clickEvent) => handleClick(clickEvent, id)}>Click</button>
Why developers use ‘e’:
// 'e' is short and widely recognized
const handleClick = (e) => {
console.log(e.target);
};
// 'event' is more descriptive but longer
const handleClick = (event) => {
console.log(event.target);
};
// Custom names work but might confuse other developers
const handleClick = (banana) => {
console.log(banana.target); // Works but confusing!
};
Best Practice:
// Use 'e' for short inline handlers
<button onClick={(e) => e.preventDefault()}>Click</button>
// Use 'event' for longer, more complex handlers
const handleSubmit = (event) => {
event.preventDefault();
event.stopPropagation();
// ... more logic
};
3. Event Methods and Properties Explained
Explain preventDefault, stopPropagation, currentTarget, target, type etc.
Let me create a comprehensive example:
const EventDemo = () => {
const handleClick = (e) => {
console.log('=== EVENT PROPERTIES ===');
console.log('e.type:', e.type); // "click"
console.log('e.target:', e.target); // Element that triggered event
console.log('e.currentTarget:', e.currentTarget); // Element with event listener
console.log('=== EVENT METHODS ===');
// e.preventDefault(); // Prevents default behavior
// e.stopPropagation(); // Stops event from bubbling up
};
return (
<div onClick={handleClick} style={{padding: '20px', border: '1px solid blue'}}>
<h3>Parent Div</h3>
<button onClick={handleClick}>Child Button</button>
</div>
);
};
e.target vs e.currentTarget:
const Example = () => {
const handleClick = (e) => {
console.log('target:', e.target.tagName); // What you clicked
console.log('currentTarget:', e.currentTarget.tagName); // What has the listener
};
return (
<div onClick={handleClick}> {/* currentTarget will be DIV */}
<button>Click me</button> {/* target will be BUTTON */}
</div>
);
};
preventDefault() – Stops Default Browser Behavior:
const FormExample = () => {
const handleSubmit = (e) => {
e.preventDefault(); // Prevents form from submitting and page refresh
console.log('Form submitted via JavaScript instead!');
};
const handleLinkClick = (e) => {
e.preventDefault(); // Prevents link from navigating
console.log('Link clicked but not navigating!');
};
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" />
<button type="submit">Submit</button>
</form>
<a href="https://google.com" onClick={handleLinkClick}>
This link won't navigate
</a>
</div>
);
};
stopPropagation() – Stops Event Bubbling:
const BubblingExample = () => {
const handleParentClick = () => {
console.log('Parent clicked!');
};
const handleChildClick = (e) => {
console.log('Child clicked!');
e.stopPropagation(); // Prevents parent from also firing
};
return (
<div onClick={handleParentClick} style={{padding: '20px', backgroundColor: 'lightblue'}}>
Parent
<button onClick={handleChildClick}>
Child (click me - parent won't fire)
</button>
</div>
);
};
e.type – Event Type:
const MultiEventExample = () => {
const handleEvent = (e) => {
switch(e.type) {
case 'click':
console.log('Button was clicked!');
break;
case 'mouseenter':
console.log('Mouse entered button!');
break;
case 'mouseleave':
console.log('Mouse left button!');
break;
}
};
return (
<button
onClick={handleEvent}
onMouseEnter={handleEvent}
onMouseLeave={handleEvent}
>
Multi-event button
</button>
);
};
4. React Props 📦 Explained
Props (properties) are how you pass data from parent components to child components.
Basic Props Example:
// Parent component
const App = () => {
const userName = "John";
const userAge = 25;
return (
<div>
<UserCard name={userName} age={userAge} />
</div>
);
};
// Child component receives props
const UserCard = (props) => {
return (
<div>
<h2>Name: {props.name}</h2>
<p>Age: {props.age}</p>
</div>
);
};
Props with Destructuring (More Common):
// Instead of using props.name, props.age
const UserCard = ({ name, age }) => {
return (
<div>
<h2>Name: {name}</h2>
<p>Age: {age}</p>
</div>
);
};
Different Types of Props:
const ComponentExample = () => {
const user = { name: "Alice", email: "alice@example.com" };
const numbers = [1, 2, 3, 4, 5];
const isActive = true;
return (
<MyComponent
// String prop
title="Hello World"
// Number prop
count={42}
// Boolean prop
isVisible={isActive}
// Object prop
user={user}
// Array prop
items={numbers}
// Function prop
onButtonClick={() => console.log('Clicked!')}
/>
);
};
const MyComponent = ({ title, count, isVisible, user, items, onButtonClick }) => {
return (
<div>
<h1>{title}</h1>
<p>Count: {count}</p>
{isVisible && <p>This is visible!</p>}
<p>User: {user.name} ({user.email})</p>
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
<button onClick={onButtonClick}>Click me</button>
</div>
);
};
Props in Our Todo App:
// We can break our todo app into smaller components
const TodoApp = () => {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
const addTodo = () => {
// ... add todo logic
};
const deleteTodo = (id) => {
// ... delete todo logic
};
return (
<div>
<AddTodoForm
value={inputValue}
onChange={setInputValue}
onAdd={addTodo}
/>
<TodoList
todos={todos}
onDelete={deleteTodo}
/>
</div>
);
};
// Child component receives props
const AddTodoForm = ({ value, onChange, onAdd }) => {
return (
<div>
<input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
<button onClick={onAdd}>Add Todo</button>
</div>
);
};
const TodoList = ({ todos, onDelete }) => {
return (
<ul>
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onDelete={onDelete}
/>
))}
</ul>
);
};
const TodoItem = ({ todo, onDelete }) => {
return (
<li>
{todo.text}
<button onClick={() => onDelete(todo.id)}>Delete</button>
</li>
);
};
Props Rules:
- Props are read-only – child components cannot modify props
- Props flow down – from parent to child, not the other way up
- Props can be any data type – strings, numbers, objects, arrays, functions
- Props are optional – you can provide default values
// Default props
const Greeting = ({ name = "World", enthusiasm = 1 }) => {
return <h1>Hello {name}{"!".repeat(enthusiasm)}</h1>;
};
// Usage
<Greeting /> // "Hello World!"
<Greeting name="Alice" /> // "Hello Alice!"
<Greeting name="Bob" enthusiasm={3} /> // "Hello Bob!!!"
🎯 Summary:
- Event Delegation = One listener handles many elements = Better performance
- Event parameter naming = Use any name you want (
e,event,evt,v, etc.) - Event methods:
preventDefault()stops default behavior,stopPropagation()stops bubbling - Event properties:
target= what triggered event,currentTarget= what has listener - Props = Data passed from parent to child components
Let’s see in Part 5. Happy React Development! 🚀