Episode 2 — React Frontend Architecture NextJS / 2.5 — Event Handling and Conditional Rendering
2.5 — Event Handling & Conditional Rendering: Quick Revision
Compact cheat sheet. Print-friendly.
How to use this material:
- Scan before an interview or exam.
- Use as a quick reference during coding.
- If anything is unclear, refer to the full sub-topic file.
- Covers ALL key concepts from 2.5.a through 2.5.e.
2.5.a — Handling Click Events
| Concept | Key Point |
|---|---|
| SyntheticEvent | Cross-browser wrapper around native events |
| Event naming | camelCase: onClick, onChange, onKeyDown |
| Pass reference | onClick={fn} ✅ not onClick={fn()} ❌ |
| Pass arguments | onClick={() => fn(id)} or currying onClick={fn(id)} |
event.target | Element that was actually clicked |
event.currentTarget | Element the handler is attached to |
preventDefault() | Cancels browser default (form submit, link navigate) |
stopPropagation() | Stops event from reaching parent handlers |
| Handler naming | Inside: handleClick, Props: onClick |
| Delegation | React handles it automatically at root level |
Event flow: Capture (top→target) → Target → Bubble (target→top)
// Pattern: Button inside clickable card
function Card({ onOpen, onDelete }) {
return (
<div onClick={onOpen}>
<button onClick={(e) => { e.stopPropagation(); onDelete(); }}>Delete</button>
</div>
);
}
2.5.b — Controlled Inputs
| Input Type | Value Prop | Change Handler |
|---|---|---|
| Text/Email | value={state} | onChange={e => set(e.target.value)} |
| Textarea | value={state} | onChange={e => set(e.target.value)} |
| Select | value={state} | onChange={e => set(e.target.value)} |
| Checkbox | checked={state} | onChange={e => set(e.target.checked)} |
| Radio | checked={state === val} | onChange={e => set(e.target.value)} |
| File | Cannot be controlled | onChange={e => handle(e.target.files)} |
Single handler for all fields:
function handleChange(e) {
const { name, value, type, checked } = e.target;
setForm(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : value }));
}
// Each input: <input name="email" value={form.email} onChange={handleChange} />
Common mistakes:
valuewithoutonChange= frozen input (usereadOnlyordefaultValue)- Using
valuefor checkbox instead ofchecked - Setting value to
undefined/null= switches to uncontrolled
2.5.c — Conditional Rendering Patterns
| Pattern | Syntax | Best For |
|---|---|---|
&& | {show && <X />} | Show or nothing |
| Ternary | {a ? <X /> : <Y />} | Show A or B |
| Early return | if (!data) return null | Loading/error guards |
| if/else variable | let content; if... | Complex multi-branch |
| switch | switch(status) { case... } | 4+ branches |
| Object lookup | map[key] || fallback | Config-driven mapping |
The 0 gotcha:
{count && <X />} // ❌ Renders "0" when count = 0
{count > 0 && <X />} // ✅ Fix
What renders nothing: false, null, undefined, "", true
What renders as text: 0 → "0", NaN → "NaN"
Conditional rendering vs CSS hiding:
| Unmounts? | Preserves State? | Use For | |
|---|---|---|---|
{show && <X />} | Yes | No | Modals, conditional sections |
display: none | No | Yes | Tabs, sidebars |
2.5.d — Dynamic UI Patterns
| Pattern | State | Key Technique |
|---|---|---|
| Toggle | const [isOpen, setIsOpen] = useState(false) | {isOpen && <Content />} |
| Tabs | const [activeTab, setActiveTab] = useState(0) | Render tabs[activeTab].content |
| Accordion (single) | const [openIndex, setOpenIndex] = useState(null) | Toggle: set(prev === i ? null : i) |
| Accordion (multi) | const [open, setOpen] = useState(new Set()) | Toggle with Set add/delete |
| Modal | const [showModal, setShowModal] = useState(false) | Portal + backdrop + Escape key |
| Dropdown | const [isOpen, setIsOpen] = useState(false) | Outside click detection with ref |
Modal essentials: createPortal, Escape listener, backdrop click, stopPropagation on content, body scroll lock, focus management.
Outside click detection:
useEffect(() => {
function handler(e) {
if (ref.current && !ref.current.contains(e.target)) setIsOpen(false);
}
document.addEventListener('mousedown', handler);
return () => document.removeEventListener('mousedown', handler);
}, []);
ARIA quick reference:
| Component | Key ARIA |
|---|---|
| Modal | role="dialog", aria-modal="true", aria-labelledby |
| Tabs | role="tablist", role="tab", aria-selected |
| Accordion | aria-expanded, aria-controls |
| Dropdown | aria-haspopup, aria-expanded |
2.5.e — Form Architecture
Form state model:
const [values, setValues] = useState({...}); // Field values
const [errors, setErrors] = useState({}); // Validation errors
const [touched, setTouched] = useState({}); // Has field been blurred?
Validation strategy:
- Validate on blur (first touch)
- Re-validate on change (after touched)
- Validate all step fields on Next click
Multi-step form:
Step fields map → Per-step validation → Navigate if valid → Review → Submit
Reusable form hook pattern:
const { values, errors, touched, handleChange, handleBlur, validateFields } = useForm(
initialValues,
validationRules
);
Decision Quick-Reference
Need to show/hide one thing? → && operator
Need to show A or B? → Ternary
Need loading/error guards? → Early return
Need 4+ branches on one value? → Object lookup
Need complex per-branch logic? → switch or if/else
Need to preserve hidden state? → CSS display:none
Need to destroy hidden state? → Conditional rendering
For deeper explanations, see 2.5 sub-topic files.