[{"data":1,"prerenderedAt":1861},["ShallowReactive",2],{"blog-\u002Fblog\u002Freact-event-handling-guide":3},{"id":4,"title":5,"body":6,"description":1845,"difficulty":1846,"extension":1847,"framework":1848,"frameworkSlug":1849,"meta":1850,"navigation":125,"order":122,"path":1852,"qaPath":1853,"seo":1854,"stem":1855,"subtopic":1856,"topic":1857,"topicSlug":1858,"updated":1859,"__hash__":1860},"blog\u002Fblog\u002Freact-event-handling-guide.md","React Event Handling — A Complete Interview Guide",{"type":7,"value":8,"toc":1832},"minimark",[9,14,23,39,50,54,57,214,229,233,252,346,368,377,381,384,404,580,594,607,611,614,746,753,826,829,833,854,864,984,994,998,1013,1138,1161,1165,1179,1382,1386,1393,1538,1548,1552,1559,1783,1789,1793,1796,1825,1828],[10,11,13],"h2",{"id":12},"how-reacts-event-system-works","How React's event system works",[15,16,17,18,22],"p",{},"React's event system is one of those areas where the surface looks simple\n(write ",[19,20,21],"code",{},"onClick",", get a callback) but the internals have important implications\nthat interviewers probe regularly.",[15,24,25,26,30,31,34,35,38],{},"The key insight: React does ",[27,28,29],"strong",{},"not"," attach event listeners directly to individual\nDOM nodes. Instead it registers a single listener at the root (the\n",[19,32,33],{},"document.getElementById('root')"," container) and catches all events via bubbling.\nThis is ",[27,36,37],{},"event delegation"," — the same pattern used by jQuery and virtual scroll\nlibraries.",[15,40,41,42,45,46,49],{},"Prior to React 17, all events delegated to ",[19,43,44],{},"document",". In React 17+, they\ndelegate to the ",[27,47,48],{},"React root element"," — a change that makes it safe to embed\nmultiple React apps on one page without cross-app event interference.",[10,51,53],{"id":52},"the-basics-attaching-handlers","The basics: attaching handlers",[15,55,56],{},"Pass a function reference as a camelCase prop. No parentheses — you're passing\nthe function, not calling it.",[58,59,64],"pre",{"className":60,"code":61,"language":62,"meta":63,"style":63},"language-jsx shiki shiki-themes github-light github-dark","function ClickCounter() {\n  const [count, setCount] = useState(0)\n\n  function handleClick() {\n    setCount(c => c + 1)\n  }\n\n  \u002F\u002F onClick receives the function reference\n  return \u003Cbutton onClick={handleClick}>Clicked {count} times\u003C\u002Fbutton>\n}\n","jsx","",[19,65,66,83,120,127,138,164,170,175,182,208],{"__ignoreMap":63},[67,68,71,75,79],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"szBVR","function",[67,76,78],{"class":77},"sScJk"," ClickCounter",[67,80,82],{"class":81},"sVt8B","() {\n",[67,84,86,89,92,96,99,102,105,108,111,114,117],{"class":69,"line":85},2,[67,87,88],{"class":73},"  const",[67,90,91],{"class":81}," [",[67,93,95],{"class":94},"sj4cs","count",[67,97,98],{"class":81},", ",[67,100,101],{"class":94},"setCount",[67,103,104],{"class":81},"] ",[67,106,107],{"class":73},"=",[67,109,110],{"class":77}," useState",[67,112,113],{"class":81},"(",[67,115,116],{"class":94},"0",[67,118,119],{"class":81},")\n",[67,121,123],{"class":69,"line":122},3,[67,124,126],{"emptyLinePlaceholder":125},true,"\n",[67,128,130,133,136],{"class":69,"line":129},4,[67,131,132],{"class":73},"  function",[67,134,135],{"class":77}," handleClick",[67,137,82],{"class":81},[67,139,141,144,146,150,153,156,159,162],{"class":69,"line":140},5,[67,142,143],{"class":77},"    setCount",[67,145,113],{"class":81},[67,147,149],{"class":148},"s4XuR","c",[67,151,152],{"class":73}," =>",[67,154,155],{"class":81}," c ",[67,157,158],{"class":73},"+",[67,160,161],{"class":94}," 1",[67,163,119],{"class":81},[67,165,167],{"class":69,"line":166},6,[67,168,169],{"class":81},"  }\n",[67,171,173],{"class":69,"line":172},7,[67,174,126],{"emptyLinePlaceholder":125},[67,176,178],{"class":69,"line":177},8,[67,179,181],{"class":180},"sJ8bj","  \u002F\u002F onClick receives the function reference\n",[67,183,185,188,191,195,198,200,203,205],{"class":69,"line":184},9,[67,186,187],{"class":73},"  return",[67,189,190],{"class":81}," \u003C",[67,192,194],{"class":193},"s9eBZ","button",[67,196,197],{"class":77}," onClick",[67,199,107],{"class":73},[67,201,202],{"class":81},"{handleClick}>Clicked {count} times\u003C\u002F",[67,204,194],{"class":193},[67,206,207],{"class":81},">\n",[67,209,211],{"class":69,"line":210},10,[67,212,213],{"class":81},"}\n",[15,215,216,217,220,221,224,225,228],{},"The most common mistake: ",[19,218,219],{},"onClick={handleClick()}"," — this calls ",[19,222,223],{},"handleClick","\nduring render and passes its return value (likely ",[19,226,227],{},"undefined",") as the prop.",[10,230,232],{"id":231},"syntheticevent","SyntheticEvent",[15,234,235,236,238,239,98,242,98,245,98,248,251],{},"Every React event handler receives a ",[27,237,232],{}," — a cross-browser\nwrapper around the native DOM event. It exposes the same interface\n(",[19,240,241],{},"target",[19,243,244],{},"currentTarget",[19,246,247],{},"preventDefault()",[19,249,250],{},"stopPropagation()",", etc.) but\nworks consistently across all browsers.",[58,253,255],{"className":60,"code":254,"language":62,"meta":63,"style":63},"function Input() {\n  function handleChange(e) {\n    \u002F\u002F e is a SyntheticEvent with the same API as a native InputEvent\n    console.log(e.target.value)\n    console.log(e.type)          \u002F\u002F 'change'\n    console.log(e.nativeEvent)   \u002F\u002F the raw browser Event object\n  }\n  return \u003Cinput onChange={handleChange} \u002F>\n}\n",[19,256,257,266,281,286,297,309,321,325,342],{"__ignoreMap":63},[67,258,259,261,264],{"class":69,"line":70},[67,260,74],{"class":73},[67,262,263],{"class":77}," Input",[67,265,82],{"class":81},[67,267,268,270,273,275,278],{"class":69,"line":85},[67,269,132],{"class":73},[67,271,272],{"class":77}," handleChange",[67,274,113],{"class":81},[67,276,277],{"class":148},"e",[67,279,280],{"class":81},") {\n",[67,282,283],{"class":69,"line":122},[67,284,285],{"class":180},"    \u002F\u002F e is a SyntheticEvent with the same API as a native InputEvent\n",[67,287,288,291,294],{"class":69,"line":129},[67,289,290],{"class":81},"    console.",[67,292,293],{"class":77},"log",[67,295,296],{"class":81},"(e.target.value)\n",[67,298,299,301,303,306],{"class":69,"line":140},[67,300,290],{"class":81},[67,302,293],{"class":77},[67,304,305],{"class":81},"(e.type)          ",[67,307,308],{"class":180},"\u002F\u002F 'change'\n",[67,310,311,313,315,318],{"class":69,"line":166},[67,312,290],{"class":81},[67,314,293],{"class":77},[67,316,317],{"class":81},"(e.nativeEvent)   ",[67,319,320],{"class":180},"\u002F\u002F the raw browser Event object\n",[67,322,323],{"class":69,"line":172},[67,324,169],{"class":81},[67,326,327,329,331,334,337,339],{"class":69,"line":177},[67,328,187],{"class":73},[67,330,190],{"class":81},[67,332,333],{"class":193},"input",[67,335,336],{"class":77}," onChange",[67,338,107],{"class":73},[67,340,341],{"class":81},"{handleChange} \u002F>\n",[67,343,344],{"class":69,"line":184},[67,345,213],{"class":81},[15,347,348,351,352,355,356,359,360,363,364,367],{},[27,349,350],{},"React 17 change — pooling removed:"," before React 17, synthetic events were\npooled and reused. After the handler returned, React reset all properties to\n",[19,353,354],{},"null",". Accessing ",[19,357,358],{},"e.target.value"," inside a ",[19,361,362],{},"setTimeout"," would crash. The fix\nwas ",[19,365,366],{},"e.persist()",".",[15,369,370,371,373,374,376],{},"React 17 removed pooling entirely. Synthetic events are now normal objects —\nyou can access them asynchronously without ",[19,372,366],{},". If you see ",[19,375,366],{},"\nin modern code, it's a legacy habit (it's a no-op now).",[10,378,380],{"id":379},"preventdefault-and-stoppropagation","preventDefault and stopPropagation",[15,382,383],{},"These are two completely independent calls:",[385,386,387,396],"ul",{},[388,389,390,395],"li",{},[27,391,392],{},[19,393,394],{},"e.preventDefault()"," — stops the browser's built-in action for this event\n(form POST, link navigation, checkbox toggle). The event continues to bubble.",[388,397,398,403],{},[27,399,400],{},[19,401,402],{},"e.stopPropagation()"," — stops the event from bubbling further up the DOM.\nParent handlers won't fire. The browser action is unaffected.",[58,405,407],{"className":60,"code":406,"language":62,"meta":63,"style":63},"function Nav() {\n  return (\n    \u003Cnav onClick={() => console.log('nav clicked')}>\n      \u003Ca\n        href=\"\u002Fprofile\"\n        onClick={e => {\n          e.preventDefault()    \u002F\u002F don't navigate to \u002Fprofile\n          e.stopPropagation()   \u002F\u002F don't trigger nav's onClick\n          openModal('profile')\n        }}\n      >\n        Profile\n      \u003C\u002Fa>\n    \u003C\u002Fnav>\n  )\n}\n",[19,408,409,418,425,457,465,475,492,506,519,531,536,542,548,559,569,575],{"__ignoreMap":63},[67,410,411,413,416],{"class":69,"line":70},[67,412,74],{"class":73},[67,414,415],{"class":77}," Nav",[67,417,82],{"class":81},[67,419,420,422],{"class":69,"line":85},[67,421,187],{"class":73},[67,423,424],{"class":81}," (\n",[67,426,427,430,433,435,437,440,443,446,448,450,454],{"class":69,"line":122},[67,428,429],{"class":81},"    \u003C",[67,431,432],{"class":193},"nav",[67,434,197],{"class":77},[67,436,107],{"class":73},[67,438,439],{"class":81},"{() ",[67,441,442],{"class":73},"=>",[67,444,445],{"class":81}," console.",[67,447,293],{"class":77},[67,449,113],{"class":81},[67,451,453],{"class":452},"sZZnC","'nav clicked'",[67,455,456],{"class":81},")}>\n",[67,458,459,462],{"class":69,"line":129},[67,460,461],{"class":81},"      \u003C",[67,463,464],{"class":193},"a\n",[67,466,467,470,472],{"class":69,"line":140},[67,468,469],{"class":77},"        href",[67,471,107],{"class":73},[67,473,474],{"class":452},"\"\u002Fprofile\"\n",[67,476,477,480,482,485,487,489],{"class":69,"line":166},[67,478,479],{"class":77},"        onClick",[67,481,107],{"class":73},[67,483,484],{"class":81},"{",[67,486,277],{"class":148},[67,488,152],{"class":73},[67,490,491],{"class":81}," {\n",[67,493,494,497,500,503],{"class":69,"line":172},[67,495,496],{"class":81},"          e.",[67,498,499],{"class":77},"preventDefault",[67,501,502],{"class":81},"()    ",[67,504,505],{"class":180},"\u002F\u002F don't navigate to \u002Fprofile\n",[67,507,508,510,513,516],{"class":69,"line":177},[67,509,496],{"class":81},[67,511,512],{"class":77},"stopPropagation",[67,514,515],{"class":81},"()   ",[67,517,518],{"class":180},"\u002F\u002F don't trigger nav's onClick\n",[67,520,521,524,526,529],{"class":69,"line":184},[67,522,523],{"class":77},"          openModal",[67,525,113],{"class":81},[67,527,528],{"class":452},"'profile'",[67,530,119],{"class":81},[67,532,533],{"class":69,"line":210},[67,534,535],{"class":81},"        }}\n",[67,537,539],{"class":69,"line":538},11,[67,540,541],{"class":81},"      >\n",[67,543,545],{"class":69,"line":544},12,[67,546,547],{"class":81},"        Profile\n",[67,549,551,554,557],{"class":69,"line":550},13,[67,552,553],{"class":81},"      \u003C\u002F",[67,555,556],{"class":193},"a",[67,558,207],{"class":81},[67,560,562,565,567],{"class":69,"line":561},14,[67,563,564],{"class":81},"    \u003C\u002F",[67,566,432],{"class":193},[67,568,207],{"class":81},[67,570,572],{"class":69,"line":571},15,[67,573,574],{"class":81},"  )\n",[67,576,578],{"class":69,"line":577},16,[67,579,213],{"class":81},[15,581,582,583,586,587,590,591,593],{},"You cannot return ",[19,584,585],{},"false"," to achieve this — unlike raw HTML ",[19,588,589],{},"onclick"," handlers,\nreturning ",[19,592,585],{}," from a React handler has no effect. React ignores the return\nvalue.",[15,595,596,597,599,600,606],{},"Call ",[19,598,247],{}," ",[27,601,602,603],{},"before any ",[19,604,605],{},"await"," — after the event handler yields,\nthe browser may have already run the default action.",[10,608,610],{"id":609},"passing-arguments-to-handlers","Passing arguments to handlers",[15,612,613],{},"Wrap the handler in an arrow function to forward arguments:",[58,615,617],{"className":60,"code":616,"language":62,"meta":63,"style":63},"function ItemList({ items, onRemove }) {\n  return (\n    \u003Cul>\n      {items.map(item => (\n        \u003Cli key={item.id}>\n          {item.name}\n          \u003Cbutton onClick={() => onRemove(item.id)}>Remove\u003C\u002Fbutton>\n        \u003C\u002Fli>\n      ))}\n    \u003C\u002Ful>\n  )\n}\n",[19,618,619,640,646,654,671,686,691,716,725,730,738,742],{"__ignoreMap":63},[67,620,621,623,626,629,632,634,637],{"class":69,"line":70},[67,622,74],{"class":73},[67,624,625],{"class":77}," ItemList",[67,627,628],{"class":81},"({ ",[67,630,631],{"class":148},"items",[67,633,98],{"class":81},[67,635,636],{"class":148},"onRemove",[67,638,639],{"class":81}," }) {\n",[67,641,642,644],{"class":69,"line":85},[67,643,187],{"class":73},[67,645,424],{"class":81},[67,647,648,650,652],{"class":69,"line":122},[67,649,429],{"class":81},[67,651,385],{"class":193},[67,653,207],{"class":81},[67,655,656,659,662,664,667,669],{"class":69,"line":129},[67,657,658],{"class":81},"      {items.",[67,660,661],{"class":77},"map",[67,663,113],{"class":81},[67,665,666],{"class":148},"item",[67,668,152],{"class":73},[67,670,424],{"class":81},[67,672,673,676,678,681,683],{"class":69,"line":140},[67,674,675],{"class":81},"        \u003C",[67,677,388],{"class":193},[67,679,680],{"class":77}," key",[67,682,107],{"class":73},[67,684,685],{"class":81},"{item.id}>\n",[67,687,688],{"class":69,"line":166},[67,689,690],{"class":81},"          {item.name}\n",[67,692,693,696,698,700,702,704,706,709,712,714],{"class":69,"line":172},[67,694,695],{"class":81},"          \u003C",[67,697,194],{"class":193},[67,699,197],{"class":77},[67,701,107],{"class":73},[67,703,439],{"class":81},[67,705,442],{"class":73},[67,707,708],{"class":77}," onRemove",[67,710,711],{"class":81},"(item.id)}>Remove\u003C\u002F",[67,713,194],{"class":193},[67,715,207],{"class":81},[67,717,718,721,723],{"class":69,"line":177},[67,719,720],{"class":81},"        \u003C\u002F",[67,722,388],{"class":193},[67,724,207],{"class":81},[67,726,727],{"class":69,"line":184},[67,728,729],{"class":81},"      ))}\n",[67,731,732,734,736],{"class":69,"line":210},[67,733,564],{"class":81},[67,735,385],{"class":193},[67,737,207],{"class":81},[67,739,740],{"class":69,"line":538},[67,741,574],{"class":81},[67,743,744],{"class":69,"line":544},[67,745,213],{"class":81},[15,747,748,749,752],{},"The arrow function creates a new function per render. For large lists where this\nis measurably expensive, use ",[19,750,751],{},"data-*"," attributes to avoid per-item closures:",[58,754,756],{"className":60,"code":755,"language":62,"meta":63,"style":63},"function handleRemove(e) {\n  const id = e.currentTarget.dataset.id\n  onRemove(id)\n}\n\n\u003Cbutton data-id={item.id} onClick={handleRemove}>Remove\u003C\u002Fbutton>\n",[19,757,758,771,784,792,796,800],{"__ignoreMap":63},[67,759,760,762,765,767,769],{"class":69,"line":70},[67,761,74],{"class":73},[67,763,764],{"class":77}," handleRemove",[67,766,113],{"class":81},[67,768,277],{"class":148},[67,770,280],{"class":81},[67,772,773,775,778,781],{"class":69,"line":85},[67,774,88],{"class":73},[67,776,777],{"class":94}," id",[67,779,780],{"class":73}," =",[67,782,783],{"class":81}," e.currentTarget.dataset.id\n",[67,785,786,789],{"class":69,"line":122},[67,787,788],{"class":77},"  onRemove",[67,790,791],{"class":81},"(id)\n",[67,793,794],{"class":69,"line":129},[67,795,213],{"class":81},[67,797,798],{"class":69,"line":140},[67,799,126],{"emptyLinePlaceholder":125},[67,801,802,805,807,810,812,815,817,819,822,824],{"class":69,"line":166},[67,803,804],{"class":81},"\u003C",[67,806,194],{"class":193},[67,808,809],{"class":77}," data-id",[67,811,107],{"class":73},[67,813,814],{"class":81},"{item.id} ",[67,816,21],{"class":77},[67,818,107],{"class":73},[67,820,821],{"class":81},"{handleRemove}>Remove\u003C\u002F",[67,823,194],{"class":193},[67,825,207],{"class":81},[15,827,828],{},"Profile before optimizing — for most lists the closure approach is fine.",[10,830,832],{"id":831},"controlled-inputs-and-onchange","Controlled inputs and onChange",[15,834,835,836,839,840,843,844,847,848,850,851,853],{},"React's ",[19,837,838],{},"onChange"," fires on ",[27,841,842],{},"every value change"," — typing, pasting, cutting —\nnot just on blur like the native DOM ",[19,845,846],{},"change"," event. This makes React's\n",[19,849,838],{}," equivalent to the native ",[19,852,333],{}," event.",[15,855,856,857,860,861,863],{},"Controlled inputs wire ",[19,858,859],{},"value"," to state and ",[19,862,838],{}," to a state setter:",[58,865,867],{"className":60,"code":866,"language":62,"meta":63,"style":63},"function SearchBox() {\n  const [query, setQuery] = useState('')\n\n  return (\n    \u003Cinput\n      type=\"search\"\n      value={query}\n      onChange={e => setQuery(e.target.value)}\n      placeholder=\"Search…\"\n    \u002F>\n  )\n}\n",[19,868,869,878,905,909,915,922,932,942,961,971,976,980],{"__ignoreMap":63},[67,870,871,873,876],{"class":69,"line":70},[67,872,74],{"class":73},[67,874,875],{"class":77}," SearchBox",[67,877,82],{"class":81},[67,879,880,882,884,887,889,892,894,896,898,900,903],{"class":69,"line":85},[67,881,88],{"class":73},[67,883,91],{"class":81},[67,885,886],{"class":94},"query",[67,888,98],{"class":81},[67,890,891],{"class":94},"setQuery",[67,893,104],{"class":81},[67,895,107],{"class":73},[67,897,110],{"class":77},[67,899,113],{"class":81},[67,901,902],{"class":452},"''",[67,904,119],{"class":81},[67,906,907],{"class":69,"line":122},[67,908,126],{"emptyLinePlaceholder":125},[67,910,911,913],{"class":69,"line":129},[67,912,187],{"class":73},[67,914,424],{"class":81},[67,916,917,919],{"class":69,"line":140},[67,918,429],{"class":81},[67,920,921],{"class":193},"input\n",[67,923,924,927,929],{"class":69,"line":166},[67,925,926],{"class":77},"      type",[67,928,107],{"class":73},[67,930,931],{"class":452},"\"search\"\n",[67,933,934,937,939],{"class":69,"line":172},[67,935,936],{"class":77},"      value",[67,938,107],{"class":73},[67,940,941],{"class":81},"{query}\n",[67,943,944,947,949,951,953,955,958],{"class":69,"line":177},[67,945,946],{"class":77},"      onChange",[67,948,107],{"class":73},[67,950,484],{"class":81},[67,952,277],{"class":148},[67,954,152],{"class":73},[67,956,957],{"class":77}," setQuery",[67,959,960],{"class":81},"(e.target.value)}\n",[67,962,963,966,968],{"class":69,"line":184},[67,964,965],{"class":77},"      placeholder",[67,967,107],{"class":73},[67,969,970],{"class":452},"\"Search…\"\n",[67,972,973],{"class":69,"line":210},[67,974,975],{"class":81},"    \u002F>\n",[67,977,978],{"class":69,"line":538},[67,979,574],{"class":81},[67,981,982],{"class":69,"line":544},[67,983,213],{"class":81},[15,985,986,987,989,990,993],{},"Every keystroke triggers a re-render. The DOM ",[19,988,859],{}," attribute stays in sync\nwith state — programmatic changes (",[19,991,992],{},"setQuery('')",") work correctly.",[10,995,997],{"id":996},"keyboard-events","Keyboard events",[15,999,1000,1001,1004,1005,1008,1009,1012],{},"Use ",[19,1002,1003],{},"onKeyDown"," for keyboard handling. Check ",[19,1006,1007],{},"e.key"," for the logical key name\n(not the deprecated ",[19,1010,1011],{},"e.keyCode","):",[58,1014,1016],{"className":60,"code":1015,"language":62,"meta":63,"style":63},"function CommandInput() {\n  function handleKeyDown(e) {\n    if (e.key === 'Enter' && !e.shiftKey) {\n      e.preventDefault()\n      submitCommand()\n    }\n    if (e.key === 'Escape') {\n      clear()\n    }\n  }\n\n  return \u003Ctextarea onKeyDown={handleKeyDown} \u002F>\n}\n",[19,1017,1018,1027,1040,1063,1073,1080,1085,1098,1105,1109,1113,1117,1134],{"__ignoreMap":63},[67,1019,1020,1022,1025],{"class":69,"line":70},[67,1021,74],{"class":73},[67,1023,1024],{"class":77}," CommandInput",[67,1026,82],{"class":81},[67,1028,1029,1031,1034,1036,1038],{"class":69,"line":85},[67,1030,132],{"class":73},[67,1032,1033],{"class":77}," handleKeyDown",[67,1035,113],{"class":81},[67,1037,277],{"class":148},[67,1039,280],{"class":81},[67,1041,1042,1045,1048,1051,1054,1057,1060],{"class":69,"line":122},[67,1043,1044],{"class":73},"    if",[67,1046,1047],{"class":81}," (e.key ",[67,1049,1050],{"class":73},"===",[67,1052,1053],{"class":452}," 'Enter'",[67,1055,1056],{"class":73}," &&",[67,1058,1059],{"class":73}," !",[67,1061,1062],{"class":81},"e.shiftKey) {\n",[67,1064,1065,1068,1070],{"class":69,"line":129},[67,1066,1067],{"class":81},"      e.",[67,1069,499],{"class":77},[67,1071,1072],{"class":81},"()\n",[67,1074,1075,1078],{"class":69,"line":140},[67,1076,1077],{"class":77},"      submitCommand",[67,1079,1072],{"class":81},[67,1081,1082],{"class":69,"line":166},[67,1083,1084],{"class":81},"    }\n",[67,1086,1087,1089,1091,1093,1096],{"class":69,"line":172},[67,1088,1044],{"class":73},[67,1090,1047],{"class":81},[67,1092,1050],{"class":73},[67,1094,1095],{"class":452}," 'Escape'",[67,1097,280],{"class":81},[67,1099,1100,1103],{"class":69,"line":177},[67,1101,1102],{"class":77},"      clear",[67,1104,1072],{"class":81},[67,1106,1107],{"class":69,"line":184},[67,1108,1084],{"class":81},[67,1110,1111],{"class":69,"line":210},[67,1112,169],{"class":81},[67,1114,1115],{"class":69,"line":538},[67,1116,126],{"emptyLinePlaceholder":125},[67,1118,1119,1121,1123,1126,1129,1131],{"class":69,"line":544},[67,1120,187],{"class":73},[67,1122,190],{"class":81},[67,1124,1125],{"class":193},"textarea",[67,1127,1128],{"class":77}," onKeyDown",[67,1130,107],{"class":73},[67,1132,1133],{"class":81},"{handleKeyDown} \u002F>\n",[67,1135,1136],{"class":69,"line":550},[67,1137,213],{"class":81},[15,1139,1140,1141,98,1144,98,1147,98,1150,1153,1154,1157,1158,1160],{},"Modifier keys: check ",[19,1142,1143],{},"e.ctrlKey",[19,1145,1146],{},"e.shiftKey",[19,1148,1149],{},"e.altKey",[19,1151,1152],{},"e.metaKey",".\n",[19,1155,1156],{},"onKeyPress"," is deprecated — use ",[19,1159,1003],{}," instead.",[10,1162,1164],{"id":1163},"form-submission","Form submission",[15,1166,1167,1168,1171,1172,1175,1176,1178],{},"Always put ",[19,1169,1170],{},"onSubmit"," on the ",[19,1173,1174],{},"\u003Cform>"," element, not ",[19,1177,21],{}," on the submit\nbutton. The form's handler fires for both mouse clicks and Enter-key presses.",[58,1180,1182],{"className":60,"code":1181,"language":62,"meta":63,"style":63},"function SignupForm() {\n  const [email, setEmail] = useState('')\n\n  async function handleSubmit(e) {\n    e.preventDefault()          \u002F\u002F prevent full-page POST\n    await createAccount(email)\n  }\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003Cinput\n        type=\"email\"\n        value={email}\n        onChange={e => setEmail(e.target.value)}\n      \u002F>\n      \u003Cbutton type=\"submit\">Sign up\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  )\n}\n",[19,1183,1184,1193,1219,1223,1240,1253,1264,1268,1272,1278,1293,1299,1309,1319,1337,1342,1363,1372,1377],{"__ignoreMap":63},[67,1185,1186,1188,1191],{"class":69,"line":70},[67,1187,74],{"class":73},[67,1189,1190],{"class":77}," SignupForm",[67,1192,82],{"class":81},[67,1194,1195,1197,1199,1202,1204,1207,1209,1211,1213,1215,1217],{"class":69,"line":85},[67,1196,88],{"class":73},[67,1198,91],{"class":81},[67,1200,1201],{"class":94},"email",[67,1203,98],{"class":81},[67,1205,1206],{"class":94},"setEmail",[67,1208,104],{"class":81},[67,1210,107],{"class":73},[67,1212,110],{"class":77},[67,1214,113],{"class":81},[67,1216,902],{"class":452},[67,1218,119],{"class":81},[67,1220,1221],{"class":69,"line":122},[67,1222,126],{"emptyLinePlaceholder":125},[67,1224,1225,1228,1231,1234,1236,1238],{"class":69,"line":129},[67,1226,1227],{"class":73},"  async",[67,1229,1230],{"class":73}," function",[67,1232,1233],{"class":77}," handleSubmit",[67,1235,113],{"class":81},[67,1237,277],{"class":148},[67,1239,280],{"class":81},[67,1241,1242,1245,1247,1250],{"class":69,"line":140},[67,1243,1244],{"class":81},"    e.",[67,1246,499],{"class":77},[67,1248,1249],{"class":81},"()          ",[67,1251,1252],{"class":180},"\u002F\u002F prevent full-page POST\n",[67,1254,1255,1258,1261],{"class":69,"line":166},[67,1256,1257],{"class":73},"    await",[67,1259,1260],{"class":77}," createAccount",[67,1262,1263],{"class":81},"(email)\n",[67,1265,1266],{"class":69,"line":172},[67,1267,169],{"class":81},[67,1269,1270],{"class":69,"line":177},[67,1271,126],{"emptyLinePlaceholder":125},[67,1273,1274,1276],{"class":69,"line":184},[67,1275,187],{"class":73},[67,1277,424],{"class":81},[67,1279,1280,1282,1285,1288,1290],{"class":69,"line":210},[67,1281,429],{"class":81},[67,1283,1284],{"class":193},"form",[67,1286,1287],{"class":77}," onSubmit",[67,1289,107],{"class":73},[67,1291,1292],{"class":81},"{handleSubmit}>\n",[67,1294,1295,1297],{"class":69,"line":538},[67,1296,461],{"class":81},[67,1298,921],{"class":193},[67,1300,1301,1304,1306],{"class":69,"line":544},[67,1302,1303],{"class":77},"        type",[67,1305,107],{"class":73},[67,1307,1308],{"class":452},"\"email\"\n",[67,1310,1311,1314,1316],{"class":69,"line":550},[67,1312,1313],{"class":77},"        value",[67,1315,107],{"class":73},[67,1317,1318],{"class":81},"{email}\n",[67,1320,1321,1324,1326,1328,1330,1332,1335],{"class":69,"line":561},[67,1322,1323],{"class":77},"        onChange",[67,1325,107],{"class":73},[67,1327,484],{"class":81},[67,1329,277],{"class":148},[67,1331,152],{"class":73},[67,1333,1334],{"class":77}," setEmail",[67,1336,960],{"class":81},[67,1338,1339],{"class":69,"line":571},[67,1340,1341],{"class":81},"      \u002F>\n",[67,1343,1344,1346,1348,1351,1353,1356,1359,1361],{"class":69,"line":577},[67,1345,461],{"class":81},[67,1347,194],{"class":193},[67,1349,1350],{"class":77}," type",[67,1352,107],{"class":73},[67,1354,1355],{"class":452},"\"submit\"",[67,1357,1358],{"class":81},">Sign up\u003C\u002F",[67,1360,194],{"class":193},[67,1362,207],{"class":81},[67,1364,1366,1368,1370],{"class":69,"line":1365},17,[67,1367,564],{"class":81},[67,1369,1284],{"class":193},[67,1371,207],{"class":81},[67,1373,1375],{"class":69,"line":1374},18,[67,1376,574],{"class":81},[67,1378,1380],{"class":69,"line":1379},19,[67,1381,213],{"class":81},[10,1383,1385],{"id":1384},"debouncing-and-throttling","Debouncing and throttling",[15,1387,1388,1389,1392],{},"Debounce\u002Fthrottle wrappers must be ",[27,1390,1391],{},"stable"," across renders — don't recreate\nthem on every render or the timer resets each time.",[58,1394,1396],{"className":60,"code":1395,"language":62,"meta":63,"style":63},"function SearchInput({ onSearch }) {\n  const debouncedSearch = useRef(\n    debounce((value) => onSearch(value), 300)\n  ).current\n\n  useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch])\n\n  return (\n    \u003Cinput\n      onChange={e => debouncedSearch(e.target.value)}\n      placeholder=\"Search…\"\n    \u002F>\n  )\n}\n",[19,1397,1398,1412,1427,1453,1458,1462,1486,1490,1496,1502,1518,1526,1530,1534],{"__ignoreMap":63},[67,1399,1400,1402,1405,1407,1410],{"class":69,"line":70},[67,1401,74],{"class":73},[67,1403,1404],{"class":77}," SearchInput",[67,1406,628],{"class":81},[67,1408,1409],{"class":148},"onSearch",[67,1411,639],{"class":81},[67,1413,1414,1416,1419,1421,1424],{"class":69,"line":85},[67,1415,88],{"class":73},[67,1417,1418],{"class":94}," debouncedSearch",[67,1420,780],{"class":73},[67,1422,1423],{"class":77}," useRef",[67,1425,1426],{"class":81},"(\n",[67,1428,1429,1432,1435,1437,1440,1442,1445,1448,1451],{"class":69,"line":122},[67,1430,1431],{"class":77},"    debounce",[67,1433,1434],{"class":81},"((",[67,1436,859],{"class":148},[67,1438,1439],{"class":81},") ",[67,1441,442],{"class":73},[67,1443,1444],{"class":77}," onSearch",[67,1446,1447],{"class":81},"(value), ",[67,1449,1450],{"class":94},"300",[67,1452,119],{"class":81},[67,1454,1455],{"class":69,"line":129},[67,1456,1457],{"class":81},"  ).current\n",[67,1459,1460],{"class":69,"line":140},[67,1461,126],{"emptyLinePlaceholder":125},[67,1463,1464,1467,1470,1472,1475,1477,1480,1483],{"class":69,"line":166},[67,1465,1466],{"class":77},"  useEffect",[67,1468,1469],{"class":81},"(() ",[67,1471,442],{"class":73},[67,1473,1474],{"class":81}," () ",[67,1476,442],{"class":73},[67,1478,1479],{"class":81}," debouncedSearch.",[67,1481,1482],{"class":77},"cancel",[67,1484,1485],{"class":81},"(), [debouncedSearch])\n",[67,1487,1488],{"class":69,"line":172},[67,1489,126],{"emptyLinePlaceholder":125},[67,1491,1492,1494],{"class":69,"line":177},[67,1493,187],{"class":73},[67,1495,424],{"class":81},[67,1497,1498,1500],{"class":69,"line":184},[67,1499,429],{"class":81},[67,1501,921],{"class":193},[67,1503,1504,1506,1508,1510,1512,1514,1516],{"class":69,"line":210},[67,1505,946],{"class":77},[67,1507,107],{"class":73},[67,1509,484],{"class":81},[67,1511,277],{"class":148},[67,1513,152],{"class":73},[67,1515,1418],{"class":77},[67,1517,960],{"class":81},[67,1519,1520,1522,1524],{"class":69,"line":538},[67,1521,965],{"class":77},[67,1523,107],{"class":73},[67,1525,970],{"class":452},[67,1527,1528],{"class":69,"line":544},[67,1529,975],{"class":81},[67,1531,1532],{"class":69,"line":550},[67,1533,574],{"class":81},[67,1535,1536],{"class":69,"line":561},[67,1537,213],{"class":81},[15,1539,1540,1543,1544,1547],{},[19,1541,1542],{},"useRef"," stores the debounced function once. The cleanup ",[19,1545,1546],{},"useEffect"," cancels\nany pending timer on unmount.",[10,1549,1551],{"id":1550},"this-binding-in-class-components","This binding in class components",[15,1553,1554,1555,1558],{},"In class components, event handlers lose their ",[19,1556,1557],{},"this"," when called as callbacks.\nThree fixes, in order of preference:",[58,1560,1562],{"className":60,"code":1561,"language":62,"meta":63,"style":63},"\u002F\u002F Option 1 — class field arrow function (auto-binds, no constructor needed)\nclass Button extends React.Component {\n  handleClick = () => {\n    this.setState({ clicked: true })\n  }\n  render() {\n    return \u003Cbutton onClick={this.handleClick}>Click\u003C\u002Fbutton>\n  }\n}\n\n\u002F\u002F Option 2 — bind in constructor\nclass Button extends React.Component {\n  constructor(props) {\n    super(props)\n    this.handleClick = this.handleClick.bind(this)\n  }\n  handleClick() { … }\n}\n\n\u002F\u002F Option 3 — arrow function in JSX (creates a new function each render)\n\u003Cbutton onClick={() => this.handleClick()}>\n",[19,1563,1564,1569,1590,1603,1622,1626,1633,1657,1661,1665,1669,1674,1690,1702,1710,1734,1738,1745,1749,1753,1759],{"__ignoreMap":63},[67,1565,1566],{"class":69,"line":70},[67,1567,1568],{"class":180},"\u002F\u002F Option 1 — class field arrow function (auto-binds, no constructor needed)\n",[67,1570,1571,1574,1577,1580,1583,1585,1588],{"class":69,"line":85},[67,1572,1573],{"class":73},"class",[67,1575,1576],{"class":77}," Button",[67,1578,1579],{"class":73}," extends",[67,1581,1582],{"class":77}," React",[67,1584,367],{"class":81},[67,1586,1587],{"class":77},"Component",[67,1589,491],{"class":81},[67,1591,1592,1595,1597,1599,1601],{"class":69,"line":122},[67,1593,1594],{"class":77},"  handleClick",[67,1596,780],{"class":73},[67,1598,1474],{"class":81},[67,1600,442],{"class":73},[67,1602,491],{"class":81},[67,1604,1605,1608,1610,1613,1616,1619],{"class":69,"line":129},[67,1606,1607],{"class":94},"    this",[67,1609,367],{"class":81},[67,1611,1612],{"class":77},"setState",[67,1614,1615],{"class":81},"({ clicked: ",[67,1617,1618],{"class":94},"true",[67,1620,1621],{"class":81}," })\n",[67,1623,1624],{"class":69,"line":140},[67,1625,169],{"class":81},[67,1627,1628,1631],{"class":69,"line":166},[67,1629,1630],{"class":77},"  render",[67,1632,82],{"class":81},[67,1634,1635,1638,1640,1642,1644,1646,1648,1650,1653,1655],{"class":69,"line":172},[67,1636,1637],{"class":73},"    return",[67,1639,190],{"class":81},[67,1641,194],{"class":193},[67,1643,197],{"class":77},[67,1645,107],{"class":73},[67,1647,484],{"class":81},[67,1649,1557],{"class":94},[67,1651,1652],{"class":81},".handleClick}>Click\u003C\u002F",[67,1654,194],{"class":193},[67,1656,207],{"class":81},[67,1658,1659],{"class":69,"line":177},[67,1660,169],{"class":81},[67,1662,1663],{"class":69,"line":184},[67,1664,213],{"class":81},[67,1666,1667],{"class":69,"line":210},[67,1668,126],{"emptyLinePlaceholder":125},[67,1670,1671],{"class":69,"line":538},[67,1672,1673],{"class":180},"\u002F\u002F Option 2 — bind in constructor\n",[67,1675,1676,1678,1680,1682,1684,1686,1688],{"class":69,"line":544},[67,1677,1573],{"class":73},[67,1679,1576],{"class":77},[67,1681,1579],{"class":73},[67,1683,1582],{"class":77},[67,1685,367],{"class":81},[67,1687,1587],{"class":77},[67,1689,491],{"class":81},[67,1691,1692,1695,1697,1700],{"class":69,"line":550},[67,1693,1694],{"class":73},"  constructor",[67,1696,113],{"class":81},[67,1698,1699],{"class":148},"props",[67,1701,280],{"class":81},[67,1703,1704,1707],{"class":69,"line":561},[67,1705,1706],{"class":94},"    super",[67,1708,1709],{"class":81},"(props)\n",[67,1711,1712,1714,1717,1719,1722,1725,1728,1730,1732],{"class":69,"line":571},[67,1713,1607],{"class":94},[67,1715,1716],{"class":81},".handleClick ",[67,1718,107],{"class":73},[67,1720,1721],{"class":94}," this",[67,1723,1724],{"class":81},".handleClick.",[67,1726,1727],{"class":77},"bind",[67,1729,113],{"class":81},[67,1731,1557],{"class":94},[67,1733,119],{"class":81},[67,1735,1736],{"class":69,"line":577},[67,1737,169],{"class":81},[67,1739,1740,1742],{"class":69,"line":1365},[67,1741,1594],{"class":77},[67,1743,1744],{"class":81},"() { … }\n",[67,1746,1747],{"class":69,"line":1374},[67,1748,213],{"class":81},[67,1750,1751],{"class":69,"line":1379},[67,1752,126],{"emptyLinePlaceholder":125},[67,1754,1756],{"class":69,"line":1755},20,[67,1757,1758],{"class":180},"\u002F\u002F Option 3 — arrow function in JSX (creates a new function each render)\n",[67,1760,1762,1764,1766,1768,1770,1772,1774,1776,1778,1780],{"class":69,"line":1761},21,[67,1763,804],{"class":81},[67,1765,194],{"class":193},[67,1767,197],{"class":77},[67,1769,107],{"class":73},[67,1771,439],{"class":81},[67,1773,442],{"class":73},[67,1775,1721],{"class":94},[67,1777,367],{"class":81},[67,1779,223],{"class":77},[67,1781,1782],{"class":81},"()}>\n",[15,1784,1785,1786,1788],{},"Function components don't have ",[19,1787,1557],{}," at all — one less thing to worry about.",[10,1790,1792],{"id":1791},"what-interviewers-are-testing","What interviewers are testing",[15,1794,1795],{},"Event questions are checking whether you understand:",[1797,1798,1799,1804,1812,1819,1822],"ol",{},[388,1800,1801,1803],{},[27,1802,232],{}," and its cross-browser normalization role.",[388,1805,1806,1807,1809,1810,367],{},"The difference between ",[19,1808,499],{}," and ",[19,1811,512],{},[388,1813,1814,1815,1818],{},"Why ",[19,1816,1817],{},"return false"," doesn't work in React.",[388,1820,1821],{},"React 17's event delegation change and the death of event pooling.",[388,1823,1824],{},"How to pass arguments without calling the handler immediately.",[15,1826,1827],{},"The practical questions (form handling, controlled inputs, keyboard events) are\nchecking whether you can write correct React UI code, not just recite concepts.",[1829,1830,1831],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":63,"searchDepth":85,"depth":85,"links":1833},[1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844],{"id":12,"depth":85,"text":13},{"id":52,"depth":85,"text":53},{"id":231,"depth":85,"text":232},{"id":379,"depth":85,"text":380},{"id":609,"depth":85,"text":610},{"id":831,"depth":85,"text":832},{"id":996,"depth":85,"text":997},{"id":1163,"depth":85,"text":1164},{"id":1384,"depth":85,"text":1385},{"id":1550,"depth":85,"text":1551},{"id":1791,"depth":85,"text":1792},"React event handling interview questions — SyntheticEvent, camelCase events, preventDefault, stopPropagation, passing arguments, controlled inputs, and event delegation.","easy","md","React","react",{"subtopicSlug":1851},"event-handling","\u002Fblog\u002Freact-event-handling-guide","\u002Freact\u002Fcomponents\u002Fevent-handling",{"title":5,"description":1845},"blog\u002Freact-event-handling-guide","Event Handling","Components","components","2026-06-23","wRbiWUmkzih9GUlCZF41lXhU0hpxtRJksc3aG8DBob4",1782244083359]