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:

  1. Scan before an interview or exam.
  2. Use as a quick reference during coding.
  3. If anything is unclear, refer to the full sub-topic file.
  4. Covers ALL key concepts from 2.5.a through 2.5.e.

2.5.a — Handling Click Events

ConceptKey Point
SyntheticEventCross-browser wrapper around native events
Event namingcamelCase: onClick, onChange, onKeyDown
Pass referenceonClick={fn} ✅ not onClick={fn()}
Pass argumentsonClick={() => fn(id)} or currying onClick={fn(id)}
event.targetElement that was actually clicked
event.currentTargetElement the handler is attached to
preventDefault()Cancels browser default (form submit, link navigate)
stopPropagation()Stops event from reaching parent handlers
Handler namingInside: handleClick, Props: onClick
DelegationReact 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 TypeValue PropChange Handler
Text/Emailvalue={state}onChange={e => set(e.target.value)}
Textareavalue={state}onChange={e => set(e.target.value)}
Selectvalue={state}onChange={e => set(e.target.value)}
Checkboxchecked={state}onChange={e => set(e.target.checked)}
Radiochecked={state === val}onChange={e => set(e.target.value)}
FileCannot be controlledonChange={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:

  • value without onChange = frozen input (use readOnly or defaultValue)
  • Using value for checkbox instead of checked
  • Setting value to undefined/null = switches to uncontrolled

2.5.c — Conditional Rendering Patterns

PatternSyntaxBest For
&&{show && <X />}Show or nothing
Ternary{a ? <X /> : <Y />}Show A or B
Early returnif (!data) return nullLoading/error guards
if/else variablelet content; if...Complex multi-branch
switchswitch(status) { case... }4+ branches
Object lookupmap[key] || fallbackConfig-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 />}YesNoModals, conditional sections
display: noneNoYesTabs, sidebars

2.5.d — Dynamic UI Patterns

PatternStateKey Technique
Toggleconst [isOpen, setIsOpen] = useState(false){isOpen && <Content />}
Tabsconst [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
Modalconst [showModal, setShowModal] = useState(false)Portal + backdrop + Escape key
Dropdownconst [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:

ComponentKey ARIA
Modalrole="dialog", aria-modal="true", aria-labelledby
Tabsrole="tablist", role="tab", aria-selected
Accordionaria-expanded, aria-controls
Dropdownaria-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.