[{"data":1,"prerenderedAt":2537},["ShallowReactive",2],{"page-\u002Freact\u002F04-state-and-usestate":3},{"id":4,"title":5,"body":6,"description":2530,"extension":2531,"meta":2532,"navigation":61,"path":2533,"seo":2534,"stem":2535,"__hash__":2536},"content\u002Freact\u002F04-state-and-usestate.md","04 — State & useState",{"type":7,"value":8,"toc":2517},"minimark",[9,18,23,311,315,568,572,859,863,1299,1303,1491,1495,1739,1743,1961,1965,2054,2058,2177,2181,2185,2296,2421,2425,2513],[10,11,13,14],"h1",{"id":12},"_04-state-usestate","04 — State & ",[15,16,17],"code",{},"useState",[19,20,22],"h2",{"id":21},"usestate-anatomy","useState Anatomy",[24,25,28],"code-wrapper",{"filename":26,"language":27},"usestate_anatomy.js","javascript",[29,30,34],"pre",{"className":31,"code":32,"language":27,"meta":33,"style":33},"language-javascript shiki shiki-themes github-light github-dark","import { useState } from 'react'\n\n\u002F\u002F useState returns [currentState, setStateFunction]\n\u002F\u002F - currentState: the value AT THIS RENDER (snapshot, not a live reference)\n\u002F\u002F - setStateFunction: schedules a re-render with the new value\n\nconst [count, setCount] = useState(0)\n\n\u002F\u002F WHAT THE SETTER DOES:\n\u002F\u002F 1. Queues the new state value\n\u002F\u002F 2. Schedules a re-render (does NOT happen synchronously)\n\u002F\u002F 3. On next render, useState returns the NEW value\n\n\u002F\u002F CRITICAL MENTAL MODEL:\n\u002F\u002F `count` is a SNAPSHOT of state at the time this render happened.\n\u002F\u002F It does NOT update in-place when you call setCount.\n\u002F\u002F Between calling setCount and the next render, `count` is STILL the old value.\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  function handleClick() {\n    setCount(count + 1)  \u002F\u002F schedules re-render with count + 1\n    console.log(count)   \u002F\u002F STILL logs the OLD value — count is a snapshot\n  }\n  return \u003Cbutton onClick={handleClick}>{count}\u003C\u002Fbutton>\n}\n","",[15,35,36,56,63,70,76,82,87,125,130,136,142,148,154,159,165,171,177,183,188,200,226,237,258,273,279,305],{"__ignoreMap":33},[37,38,41,45,49,52],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"svdQ7","import",[37,46,48],{"class":47},"ssxIu"," { useState } ",[37,50,51],{"class":43},"from",[37,53,55],{"class":54},"sJ6F3"," 'react'\n",[37,57,59],{"class":39,"line":58},2,[37,60,62],{"emptyLinePlaceholder":61},true,"\n",[37,64,66],{"class":39,"line":65},3,[37,67,69],{"class":68},"sdCPZ","\u002F\u002F useState returns [currentState, setStateFunction]\n",[37,71,73],{"class":39,"line":72},4,[37,74,75],{"class":68},"\u002F\u002F - currentState: the value AT THIS RENDER (snapshot, not a live reference)\n",[37,77,79],{"class":39,"line":78},5,[37,80,81],{"class":68},"\u002F\u002F - setStateFunction: schedules a re-render with the new value\n",[37,83,85],{"class":39,"line":84},6,[37,86,62],{"emptyLinePlaceholder":61},[37,88,90,93,96,100,103,106,109,112,116,119,122],{"class":39,"line":89},7,[37,91,92],{"class":43},"const",[37,94,95],{"class":47}," [",[37,97,99],{"class":98},"snvgF","count",[37,101,102],{"class":47},", ",[37,104,105],{"class":98},"setCount",[37,107,108],{"class":47},"] ",[37,110,111],{"class":43},"=",[37,113,115],{"class":114},"sIsaT"," useState",[37,117,118],{"class":47},"(",[37,120,121],{"class":98},"0",[37,123,124],{"class":47},")\n",[37,126,128],{"class":39,"line":127},8,[37,129,62],{"emptyLinePlaceholder":61},[37,131,133],{"class":39,"line":132},9,[37,134,135],{"class":68},"\u002F\u002F WHAT THE SETTER DOES:\n",[37,137,139],{"class":39,"line":138},10,[37,140,141],{"class":68},"\u002F\u002F 1. Queues the new state value\n",[37,143,145],{"class":39,"line":144},11,[37,146,147],{"class":68},"\u002F\u002F 2. Schedules a re-render (does NOT happen synchronously)\n",[37,149,151],{"class":39,"line":150},12,[37,152,153],{"class":68},"\u002F\u002F 3. On next render, useState returns the NEW value\n",[37,155,157],{"class":39,"line":156},13,[37,158,62],{"emptyLinePlaceholder":61},[37,160,162],{"class":39,"line":161},14,[37,163,164],{"class":68},"\u002F\u002F CRITICAL MENTAL MODEL:\n",[37,166,168],{"class":39,"line":167},15,[37,169,170],{"class":68},"\u002F\u002F `count` is a SNAPSHOT of state at the time this render happened.\n",[37,172,174],{"class":39,"line":173},16,[37,175,176],{"class":68},"\u002F\u002F It does NOT update in-place when you call setCount.\n",[37,178,180],{"class":39,"line":179},17,[37,181,182],{"class":68},"\u002F\u002F Between calling setCount and the next render, `count` is STILL the old value.\n",[37,184,186],{"class":39,"line":185},18,[37,187,62],{"emptyLinePlaceholder":61},[37,189,191,194,197],{"class":39,"line":190},19,[37,192,193],{"class":43},"function",[37,195,196],{"class":114}," Counter",[37,198,199],{"class":47},"() {\n",[37,201,203,206,208,210,212,214,216,218,220,222,224],{"class":39,"line":202},20,[37,204,205],{"class":43},"  const",[37,207,95],{"class":47},[37,209,99],{"class":98},[37,211,102],{"class":47},[37,213,105],{"class":98},[37,215,108],{"class":47},[37,217,111],{"class":43},[37,219,115],{"class":114},[37,221,118],{"class":47},[37,223,121],{"class":98},[37,225,124],{"class":47},[37,227,229,232,235],{"class":39,"line":228},21,[37,230,231],{"class":43},"  function",[37,233,234],{"class":114}," handleClick",[37,236,199],{"class":47},[37,238,240,243,246,249,252,255],{"class":39,"line":239},22,[37,241,242],{"class":114},"    setCount",[37,244,245],{"class":47},"(count ",[37,247,248],{"class":43},"+",[37,250,251],{"class":98}," 1",[37,253,254],{"class":47},")  ",[37,256,257],{"class":68},"\u002F\u002F schedules re-render with count + 1\n",[37,259,261,264,267,270],{"class":39,"line":260},23,[37,262,263],{"class":47},"    console.",[37,265,266],{"class":114},"log",[37,268,269],{"class":47},"(count)   ",[37,271,272],{"class":68},"\u002F\u002F STILL logs the OLD value — count is a snapshot\n",[37,274,276],{"class":39,"line":275},24,[37,277,278],{"class":47},"  }\n",[37,280,282,285,288,292,295,297,300,302],{"class":39,"line":281},25,[37,283,284],{"class":43},"  return",[37,286,287],{"class":47}," \u003C",[37,289,291],{"class":290},"sk71V","button",[37,293,294],{"class":114}," onClick",[37,296,111],{"class":43},[37,298,299],{"class":47},"{handleClick}>{count}\u003C\u002F",[37,301,291],{"class":290},[37,303,304],{"class":47},">\n",[37,306,308],{"class":39,"line":307},26,[37,309,310],{"class":47},"}\n",[19,312,314],{"id":313},"functional-updates-vs-direct-values","Functional Updates vs Direct Values",[24,316,318],{"filename":317,"language":27},"functional_updates.js",[29,319,321],{"className":31,"code":320,"language":27,"meta":33,"style":33},"\u002F\u002F ANTI-PATTERN: using the current state variable directly in the update\nfunction BadCounter() {\n  const [count, setCount] = useState(0)\n  function incrementThree() {\n    setCount(count + 1)  \u002F\u002F uses count from THIS render\n    setCount(count + 1)  \u002F\u002F uses SAME count from THIS render → all three set to count + 1\n    setCount(count + 1)  \u002F\u002F result: count increases by 1, not 3\n  }\n  \u002F\u002F All three calls use the same stale `count` snapshot. React batches them\n  \u002F\u002F and applies them as three \"set to count + 1\" operations — net result: +1.\n}\n\n\u002F\u002F PRODUCTION: use the functional updater form when the next state depends on the previous\nfunction GoodCounter() {\n  const [count, setCount] = useState(0)\n  function incrementThree() {\n    setCount(prev => prev + 1)  \u002F\u002F prev is the LATEST queued state, not the render snapshot\n    setCount(prev => prev + 1)  \u002F\u002F prev = result of previous update\n    setCount(prev => prev + 1)  \u002F\u002F result: count increases by 3\n  }\n  \u002F\u002F The functional form receives the LATEST state (after all queued updates),\n  \u002F\u002F not the snapshot from the current render. Each updater builds on the previous.\n}\n",[15,322,323,328,337,361,370,385,400,415,419,424,429,433,437,442,451,475,483,508,529,550,554,559,564],{"__ignoreMap":33},[37,324,325],{"class":39,"line":40},[37,326,327],{"class":68},"\u002F\u002F ANTI-PATTERN: using the current state variable directly in the update\n",[37,329,330,332,335],{"class":39,"line":58},[37,331,193],{"class":43},[37,333,334],{"class":114}," BadCounter",[37,336,199],{"class":47},[37,338,339,341,343,345,347,349,351,353,355,357,359],{"class":39,"line":65},[37,340,205],{"class":43},[37,342,95],{"class":47},[37,344,99],{"class":98},[37,346,102],{"class":47},[37,348,105],{"class":98},[37,350,108],{"class":47},[37,352,111],{"class":43},[37,354,115],{"class":114},[37,356,118],{"class":47},[37,358,121],{"class":98},[37,360,124],{"class":47},[37,362,363,365,368],{"class":39,"line":72},[37,364,231],{"class":43},[37,366,367],{"class":114}," incrementThree",[37,369,199],{"class":47},[37,371,372,374,376,378,380,382],{"class":39,"line":78},[37,373,242],{"class":114},[37,375,245],{"class":47},[37,377,248],{"class":43},[37,379,251],{"class":98},[37,381,254],{"class":47},[37,383,384],{"class":68},"\u002F\u002F uses count from THIS render\n",[37,386,387,389,391,393,395,397],{"class":39,"line":84},[37,388,242],{"class":114},[37,390,245],{"class":47},[37,392,248],{"class":43},[37,394,251],{"class":98},[37,396,254],{"class":47},[37,398,399],{"class":68},"\u002F\u002F uses SAME count from THIS render → all three set to count + 1\n",[37,401,402,404,406,408,410,412],{"class":39,"line":89},[37,403,242],{"class":114},[37,405,245],{"class":47},[37,407,248],{"class":43},[37,409,251],{"class":98},[37,411,254],{"class":47},[37,413,414],{"class":68},"\u002F\u002F result: count increases by 1, not 3\n",[37,416,417],{"class":39,"line":127},[37,418,278],{"class":47},[37,420,421],{"class":39,"line":132},[37,422,423],{"class":68},"  \u002F\u002F All three calls use the same stale `count` snapshot. React batches them\n",[37,425,426],{"class":39,"line":138},[37,427,428],{"class":68},"  \u002F\u002F and applies them as three \"set to count + 1\" operations — net result: +1.\n",[37,430,431],{"class":39,"line":144},[37,432,310],{"class":47},[37,434,435],{"class":39,"line":150},[37,436,62],{"emptyLinePlaceholder":61},[37,438,439],{"class":39,"line":156},[37,440,441],{"class":68},"\u002F\u002F PRODUCTION: use the functional updater form when the next state depends on the previous\n",[37,443,444,446,449],{"class":39,"line":161},[37,445,193],{"class":43},[37,447,448],{"class":114}," GoodCounter",[37,450,199],{"class":47},[37,452,453,455,457,459,461,463,465,467,469,471,473],{"class":39,"line":167},[37,454,205],{"class":43},[37,456,95],{"class":47},[37,458,99],{"class":98},[37,460,102],{"class":47},[37,462,105],{"class":98},[37,464,108],{"class":47},[37,466,111],{"class":43},[37,468,115],{"class":114},[37,470,118],{"class":47},[37,472,121],{"class":98},[37,474,124],{"class":47},[37,476,477,479,481],{"class":39,"line":173},[37,478,231],{"class":43},[37,480,367],{"class":114},[37,482,199],{"class":47},[37,484,485,487,489,493,496,499,501,503,505],{"class":39,"line":179},[37,486,242],{"class":114},[37,488,118],{"class":47},[37,490,492],{"class":491},"sCrzJ","prev",[37,494,495],{"class":43}," =>",[37,497,498],{"class":47}," prev ",[37,500,248],{"class":43},[37,502,251],{"class":98},[37,504,254],{"class":47},[37,506,507],{"class":68},"\u002F\u002F prev is the LATEST queued state, not the render snapshot\n",[37,509,510,512,514,516,518,520,522,524,526],{"class":39,"line":185},[37,511,242],{"class":114},[37,513,118],{"class":47},[37,515,492],{"class":491},[37,517,495],{"class":43},[37,519,498],{"class":47},[37,521,248],{"class":43},[37,523,251],{"class":98},[37,525,254],{"class":47},[37,527,528],{"class":68},"\u002F\u002F prev = result of previous update\n",[37,530,531,533,535,537,539,541,543,545,547],{"class":39,"line":190},[37,532,242],{"class":114},[37,534,118],{"class":47},[37,536,492],{"class":491},[37,538,495],{"class":43},[37,540,498],{"class":47},[37,542,248],{"class":43},[37,544,251],{"class":98},[37,546,254],{"class":47},[37,548,549],{"class":68},"\u002F\u002F result: count increases by 3\n",[37,551,552],{"class":39,"line":202},[37,553,278],{"class":47},[37,555,556],{"class":39,"line":228},[37,557,558],{"class":68},"  \u002F\u002F The functional form receives the LATEST state (after all queued updates),\n",[37,560,561],{"class":39,"line":239},[37,562,563],{"class":68},"  \u002F\u002F not the snapshot from the current render. Each updater builds on the previous.\n",[37,565,566],{"class":39,"line":260},[37,567,310],{"class":47},[19,569,571],{"id":570},"react-18-automatic-batching","React 18 Automatic Batching",[24,573,575],{"filename":574,"language":27},"automatic_batching.js",[29,576,578],{"className":31,"code":577,"language":27,"meta":33,"style":33},"\u002F\u002F React 18 batches ALL state updates — in event handlers, timeouts, promises,\n\u002F\u002F and native event handlers. React 17 only batched inside React event handlers.\n\nfunction Search({ query }) {\n  const [results, setResults] = useState([])\n  const [loading, setLoading] = useState(false)\n  const [error, setError] = useState(null)\n\n  async function handleSearch() {\n    setLoading(true)     \u002F\u002F ─┐\n    setError(null)       \u002F\u002F ─┤ — batched: ONE re-render, not three\n    setResults([])       \u002F\u002F ─┘\n\n    try {\n      const data = await fetchResults(query)\n      setResults(data)   \u002F\u002F ─┐ batched: ONE re-render\n      setLoading(false)  \u002F\u002F ─┘\n    } catch (err) {\n      setError(err.message)  \u002F\u002F ─┐ batched: ONE re-render\n      setLoading(false)      \u002F\u002F ─┘\n    }\n  }\n  \u002F\u002F In React 17, the await boundary would UN-batch — setLoading(true) and\n  \u002F\u002F setError(null) would cause separate renders. React 18 batches everything.\n}\n",[15,579,580,585,590,594,610,633,660,687,691,704,720,735,746,750,758,778,789,802,813,823,836,841,845,850,855],{"__ignoreMap":33},[37,581,582],{"class":39,"line":40},[37,583,584],{"class":68},"\u002F\u002F React 18 batches ALL state updates — in event handlers, timeouts, promises,\n",[37,586,587],{"class":39,"line":58},[37,588,589],{"class":68},"\u002F\u002F and native event handlers. React 17 only batched inside React event handlers.\n",[37,591,592],{"class":39,"line":65},[37,593,62],{"emptyLinePlaceholder":61},[37,595,596,598,601,604,607],{"class":39,"line":72},[37,597,193],{"class":43},[37,599,600],{"class":114}," Search",[37,602,603],{"class":47},"({ ",[37,605,606],{"class":491},"query",[37,608,609],{"class":47}," }) {\n",[37,611,612,614,616,619,621,624,626,628,630],{"class":39,"line":78},[37,613,205],{"class":43},[37,615,95],{"class":47},[37,617,618],{"class":98},"results",[37,620,102],{"class":47},[37,622,623],{"class":98},"setResults",[37,625,108],{"class":47},[37,627,111],{"class":43},[37,629,115],{"class":114},[37,631,632],{"class":47},"([])\n",[37,634,635,637,639,642,644,647,649,651,653,655,658],{"class":39,"line":84},[37,636,205],{"class":43},[37,638,95],{"class":47},[37,640,641],{"class":98},"loading",[37,643,102],{"class":47},[37,645,646],{"class":98},"setLoading",[37,648,108],{"class":47},[37,650,111],{"class":43},[37,652,115],{"class":114},[37,654,118],{"class":47},[37,656,657],{"class":98},"false",[37,659,124],{"class":47},[37,661,662,664,666,669,671,674,676,678,680,682,685],{"class":39,"line":89},[37,663,205],{"class":43},[37,665,95],{"class":47},[37,667,668],{"class":98},"error",[37,670,102],{"class":47},[37,672,673],{"class":98},"setError",[37,675,108],{"class":47},[37,677,111],{"class":43},[37,679,115],{"class":114},[37,681,118],{"class":47},[37,683,684],{"class":98},"null",[37,686,124],{"class":47},[37,688,689],{"class":39,"line":127},[37,690,62],{"emptyLinePlaceholder":61},[37,692,693,696,699,702],{"class":39,"line":132},[37,694,695],{"class":43},"  async",[37,697,698],{"class":43}," function",[37,700,701],{"class":114}," handleSearch",[37,703,199],{"class":47},[37,705,706,709,711,714,717],{"class":39,"line":138},[37,707,708],{"class":114},"    setLoading",[37,710,118],{"class":47},[37,712,713],{"class":98},"true",[37,715,716],{"class":47},")     ",[37,718,719],{"class":68},"\u002F\u002F ─┐\n",[37,721,722,725,727,729,732],{"class":39,"line":144},[37,723,724],{"class":114},"    setError",[37,726,118],{"class":47},[37,728,684],{"class":98},[37,730,731],{"class":47},")       ",[37,733,734],{"class":68},"\u002F\u002F ─┤ — batched: ONE re-render, not three\n",[37,736,737,740,743],{"class":39,"line":150},[37,738,739],{"class":114},"    setResults",[37,741,742],{"class":47},"([])       ",[37,744,745],{"class":68},"\u002F\u002F ─┘\n",[37,747,748],{"class":39,"line":156},[37,749,62],{"emptyLinePlaceholder":61},[37,751,752,755],{"class":39,"line":161},[37,753,754],{"class":43},"    try",[37,756,757],{"class":47}," {\n",[37,759,760,763,766,769,772,775],{"class":39,"line":167},[37,761,762],{"class":43},"      const",[37,764,765],{"class":98}," data",[37,767,768],{"class":43}," =",[37,770,771],{"class":43}," await",[37,773,774],{"class":114}," fetchResults",[37,776,777],{"class":47},"(query)\n",[37,779,780,783,786],{"class":39,"line":173},[37,781,782],{"class":114},"      setResults",[37,784,785],{"class":47},"(data)   ",[37,787,788],{"class":68},"\u002F\u002F ─┐ batched: ONE re-render\n",[37,790,791,794,796,798,800],{"class":39,"line":179},[37,792,793],{"class":114},"      setLoading",[37,795,118],{"class":47},[37,797,657],{"class":98},[37,799,254],{"class":47},[37,801,745],{"class":68},[37,803,804,807,810],{"class":39,"line":185},[37,805,806],{"class":47},"    } ",[37,808,809],{"class":43},"catch",[37,811,812],{"class":47}," (err) {\n",[37,814,815,818,821],{"class":39,"line":190},[37,816,817],{"class":114},"      setError",[37,819,820],{"class":47},"(err.message)  ",[37,822,788],{"class":68},[37,824,825,827,829,831,834],{"class":39,"line":202},[37,826,793],{"class":114},[37,828,118],{"class":47},[37,830,657],{"class":98},[37,832,833],{"class":47},")      ",[37,835,745],{"class":68},[37,837,838],{"class":39,"line":228},[37,839,840],{"class":47},"    }\n",[37,842,843],{"class":39,"line":239},[37,844,278],{"class":47},[37,846,847],{"class":39,"line":260},[37,848,849],{"class":68},"  \u002F\u002F In React 17, the await boundary would UN-batch — setLoading(true) and\n",[37,851,852],{"class":39,"line":275},[37,853,854],{"class":68},"  \u002F\u002F setError(null) would cause separate renders. React 18 batches everything.\n",[37,856,857],{"class":39,"line":281},[37,858,310],{"class":47},[19,860,862],{"id":861},"the-stale-closure-problem","The Stale Closure Problem",[24,864,866],{"filename":865,"language":27},"stale_closure.js",[29,867,869],{"className":31,"code":868,"language":27,"meta":33,"style":33},"\u002F\u002F ANTI-PATTERN: stale closure in event handlers or timers\nfunction Poller() {\n  const [count, setCount] = useState(0)\n\n  useEffect(() => {\n    const interval = setInterval(() => {\n      \u002F\u002F This closure captures `count` from the FIRST render.\n      \u002F\u002F Every interval tick uses count = 0 → setCount(0 + 1) → setCount(1) every time.\n      setCount(count + 1)\n    }, 1000)\n    return () => clearInterval(interval)\n  }, [])  \u002F\u002F empty deps → effect runs once → closure captures count = 0 forever\n\n  return \u003Cdiv>{count}\u003C\u002Fdiv>\n}\n\n\u002F\u002F FIX 1: functional updater (doesn't need count in the closure)\nfunction Poller() {\n  const [count, setCount] = useState(0)\n  useEffect(() => {\n    const interval = setInterval(() => {\n      setCount(prev => prev + 1)  \u002F\u002F prev is always the latest state\n    }, 1000)\n    return () => clearInterval(interval)\n  }, [])\n  return \u003Cdiv>{count}\u003C\u002Fdiv>\n}\n\n\u002F\u002F FIX 2: include count in the dependency array (re-creates interval each change)\nfunction Poller() {\n  const [count, setCount] = useState(0)\n  useEffect(() => {\n    const interval = setInterval(() => setCount(count + 1), 1000)\n    return () => clearInterval(interval)\n  }, [count])  \u002F\u002F re-runs effect when count changes → fresh closure\n  return \u003Cdiv>{count}\u003C\u002Fdiv>\n}\n\u002F\u002F FIX 2 clears and re-creates the interval on every count change — slightly\n\u002F\u002F less efficient but needed if the closure uses count for other logic too.\n",[15,870,871,876,885,909,913,926,945,950,955,968,978,994,1002,1006,1022,1026,1030,1035,1043,1067,1077,1093,1114,1122,1134,1139,1153,1158,1163,1169,1178,1203,1214,1245,1258,1267,1282,1287,1293],{"__ignoreMap":33},[37,872,873],{"class":39,"line":40},[37,874,875],{"class":68},"\u002F\u002F ANTI-PATTERN: stale closure in event handlers or timers\n",[37,877,878,880,883],{"class":39,"line":58},[37,879,193],{"class":43},[37,881,882],{"class":114}," Poller",[37,884,199],{"class":47},[37,886,887,889,891,893,895,897,899,901,903,905,907],{"class":39,"line":65},[37,888,205],{"class":43},[37,890,95],{"class":47},[37,892,99],{"class":98},[37,894,102],{"class":47},[37,896,105],{"class":98},[37,898,108],{"class":47},[37,900,111],{"class":43},[37,902,115],{"class":114},[37,904,118],{"class":47},[37,906,121],{"class":98},[37,908,124],{"class":47},[37,910,911],{"class":39,"line":72},[37,912,62],{"emptyLinePlaceholder":61},[37,914,915,918,921,924],{"class":39,"line":78},[37,916,917],{"class":114},"  useEffect",[37,919,920],{"class":47},"(() ",[37,922,923],{"class":43},"=>",[37,925,757],{"class":47},[37,927,928,931,934,936,939,941,943],{"class":39,"line":84},[37,929,930],{"class":43},"    const",[37,932,933],{"class":98}," interval",[37,935,768],{"class":43},[37,937,938],{"class":114}," setInterval",[37,940,920],{"class":47},[37,942,923],{"class":43},[37,944,757],{"class":47},[37,946,947],{"class":39,"line":89},[37,948,949],{"class":68},"      \u002F\u002F This closure captures `count` from the FIRST render.\n",[37,951,952],{"class":39,"line":127},[37,953,954],{"class":68},"      \u002F\u002F Every interval tick uses count = 0 → setCount(0 + 1) → setCount(1) every time.\n",[37,956,957,960,962,964,966],{"class":39,"line":132},[37,958,959],{"class":114},"      setCount",[37,961,245],{"class":47},[37,963,248],{"class":43},[37,965,251],{"class":98},[37,967,124],{"class":47},[37,969,970,973,976],{"class":39,"line":138},[37,971,972],{"class":47},"    }, ",[37,974,975],{"class":98},"1000",[37,977,124],{"class":47},[37,979,980,983,986,988,991],{"class":39,"line":144},[37,981,982],{"class":43},"    return",[37,984,985],{"class":47}," () ",[37,987,923],{"class":43},[37,989,990],{"class":114}," clearInterval",[37,992,993],{"class":47},"(interval)\n",[37,995,996,999],{"class":39,"line":150},[37,997,998],{"class":47},"  }, [])  ",[37,1000,1001],{"class":68},"\u002F\u002F empty deps → effect runs once → closure captures count = 0 forever\n",[37,1003,1004],{"class":39,"line":156},[37,1005,62],{"emptyLinePlaceholder":61},[37,1007,1008,1010,1012,1015,1018,1020],{"class":39,"line":161},[37,1009,284],{"class":43},[37,1011,287],{"class":47},[37,1013,1014],{"class":290},"div",[37,1016,1017],{"class":47},">{count}\u003C\u002F",[37,1019,1014],{"class":290},[37,1021,304],{"class":47},[37,1023,1024],{"class":39,"line":167},[37,1025,310],{"class":47},[37,1027,1028],{"class":39,"line":173},[37,1029,62],{"emptyLinePlaceholder":61},[37,1031,1032],{"class":39,"line":179},[37,1033,1034],{"class":68},"\u002F\u002F FIX 1: functional updater (doesn't need count in the closure)\n",[37,1036,1037,1039,1041],{"class":39,"line":185},[37,1038,193],{"class":43},[37,1040,882],{"class":114},[37,1042,199],{"class":47},[37,1044,1045,1047,1049,1051,1053,1055,1057,1059,1061,1063,1065],{"class":39,"line":190},[37,1046,205],{"class":43},[37,1048,95],{"class":47},[37,1050,99],{"class":98},[37,1052,102],{"class":47},[37,1054,105],{"class":98},[37,1056,108],{"class":47},[37,1058,111],{"class":43},[37,1060,115],{"class":114},[37,1062,118],{"class":47},[37,1064,121],{"class":98},[37,1066,124],{"class":47},[37,1068,1069,1071,1073,1075],{"class":39,"line":202},[37,1070,917],{"class":114},[37,1072,920],{"class":47},[37,1074,923],{"class":43},[37,1076,757],{"class":47},[37,1078,1079,1081,1083,1085,1087,1089,1091],{"class":39,"line":228},[37,1080,930],{"class":43},[37,1082,933],{"class":98},[37,1084,768],{"class":43},[37,1086,938],{"class":114},[37,1088,920],{"class":47},[37,1090,923],{"class":43},[37,1092,757],{"class":47},[37,1094,1095,1097,1099,1101,1103,1105,1107,1109,1111],{"class":39,"line":239},[37,1096,959],{"class":114},[37,1098,118],{"class":47},[37,1100,492],{"class":491},[37,1102,495],{"class":43},[37,1104,498],{"class":47},[37,1106,248],{"class":43},[37,1108,251],{"class":98},[37,1110,254],{"class":47},[37,1112,1113],{"class":68},"\u002F\u002F prev is always the latest state\n",[37,1115,1116,1118,1120],{"class":39,"line":260},[37,1117,972],{"class":47},[37,1119,975],{"class":98},[37,1121,124],{"class":47},[37,1123,1124,1126,1128,1130,1132],{"class":39,"line":275},[37,1125,982],{"class":43},[37,1127,985],{"class":47},[37,1129,923],{"class":43},[37,1131,990],{"class":114},[37,1133,993],{"class":47},[37,1135,1136],{"class":39,"line":281},[37,1137,1138],{"class":47},"  }, [])\n",[37,1140,1141,1143,1145,1147,1149,1151],{"class":39,"line":307},[37,1142,284],{"class":43},[37,1144,287],{"class":47},[37,1146,1014],{"class":290},[37,1148,1017],{"class":47},[37,1150,1014],{"class":290},[37,1152,304],{"class":47},[37,1154,1156],{"class":39,"line":1155},27,[37,1157,310],{"class":47},[37,1159,1161],{"class":39,"line":1160},28,[37,1162,62],{"emptyLinePlaceholder":61},[37,1164,1166],{"class":39,"line":1165},29,[37,1167,1168],{"class":68},"\u002F\u002F FIX 2: include count in the dependency array (re-creates interval each change)\n",[37,1170,1172,1174,1176],{"class":39,"line":1171},30,[37,1173,193],{"class":43},[37,1175,882],{"class":114},[37,1177,199],{"class":47},[37,1179,1181,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201],{"class":39,"line":1180},31,[37,1182,205],{"class":43},[37,1184,95],{"class":47},[37,1186,99],{"class":98},[37,1188,102],{"class":47},[37,1190,105],{"class":98},[37,1192,108],{"class":47},[37,1194,111],{"class":43},[37,1196,115],{"class":114},[37,1198,118],{"class":47},[37,1200,121],{"class":98},[37,1202,124],{"class":47},[37,1204,1206,1208,1210,1212],{"class":39,"line":1205},32,[37,1207,917],{"class":114},[37,1209,920],{"class":47},[37,1211,923],{"class":43},[37,1213,757],{"class":47},[37,1215,1217,1219,1221,1223,1225,1227,1229,1232,1234,1236,1238,1241,1243],{"class":39,"line":1216},33,[37,1218,930],{"class":43},[37,1220,933],{"class":98},[37,1222,768],{"class":43},[37,1224,938],{"class":114},[37,1226,920],{"class":47},[37,1228,923],{"class":43},[37,1230,1231],{"class":114}," setCount",[37,1233,245],{"class":47},[37,1235,248],{"class":43},[37,1237,251],{"class":98},[37,1239,1240],{"class":47},"), ",[37,1242,975],{"class":98},[37,1244,124],{"class":47},[37,1246,1248,1250,1252,1254,1256],{"class":39,"line":1247},34,[37,1249,982],{"class":43},[37,1251,985],{"class":47},[37,1253,923],{"class":43},[37,1255,990],{"class":114},[37,1257,993],{"class":47},[37,1259,1261,1264],{"class":39,"line":1260},35,[37,1262,1263],{"class":47},"  }, [count])  ",[37,1265,1266],{"class":68},"\u002F\u002F re-runs effect when count changes → fresh closure\n",[37,1268,1270,1272,1274,1276,1278,1280],{"class":39,"line":1269},36,[37,1271,284],{"class":43},[37,1273,287],{"class":47},[37,1275,1014],{"class":290},[37,1277,1017],{"class":47},[37,1279,1014],{"class":290},[37,1281,304],{"class":47},[37,1283,1285],{"class":39,"line":1284},37,[37,1286,310],{"class":47},[37,1288,1290],{"class":39,"line":1289},38,[37,1291,1292],{"class":68},"\u002F\u002F FIX 2 clears and re-creates the interval on every count change — slightly\n",[37,1294,1296],{"class":39,"line":1295},39,[37,1297,1298],{"class":68},"\u002F\u002F less efficient but needed if the closure uses count for other logic too.\n",[19,1300,1302],{"id":1301},"lazy-initialization","Lazy Initialization",[24,1304,1306],{"filename":1305,"language":27},"lazy_init.js",[29,1307,1309],{"className":31,"code":1308,"language":27,"meta":33,"style":33},"\u002F\u002F ANTI-PATTERN: expensive computation on every render (even though useState\n\u002F\u002F ignores the result after the first render, it STILL computes the initial value)\nfunction BadComponent() {\n  \u002F\u002F computeExpensiveValue() runs on EVERY render — useState only uses the\n  \u002F\u002F first result, but the function is still called every time.\n  const [data, setData] = useState(computeExpensiveValue())\n}\n\n\u002F\u002F PRODUCTION: lazy initializer — the function runs ONLY on the first render\nfunction GoodComponent() {\n  \u002F\u002F useState accepts a function; calls it once, uses the return value.\n  const [data, setData] = useState(() => {\n    const cached = localStorage.getItem('data')\n    return cached ? JSON.parse(cached) : computeExpensiveValue()\n  })\n  \u002F\u002F The arrow function runs ONLY on mount. On subsequent renders, useState\n  \u002F\u002F returns the current state without calling the initializer again.\n}\n",[15,1310,1311,1316,1321,1330,1335,1340,1368,1372,1376,1381,1390,1395,1419,1441,1472,1477,1482,1487],{"__ignoreMap":33},[37,1312,1313],{"class":39,"line":40},[37,1314,1315],{"class":68},"\u002F\u002F ANTI-PATTERN: expensive computation on every render (even though useState\n",[37,1317,1318],{"class":39,"line":58},[37,1319,1320],{"class":68},"\u002F\u002F ignores the result after the first render, it STILL computes the initial value)\n",[37,1322,1323,1325,1328],{"class":39,"line":65},[37,1324,193],{"class":43},[37,1326,1327],{"class":114}," BadComponent",[37,1329,199],{"class":47},[37,1331,1332],{"class":39,"line":72},[37,1333,1334],{"class":68},"  \u002F\u002F computeExpensiveValue() runs on EVERY render — useState only uses the\n",[37,1336,1337],{"class":39,"line":78},[37,1338,1339],{"class":68},"  \u002F\u002F first result, but the function is still called every time.\n",[37,1341,1342,1344,1346,1349,1351,1354,1356,1358,1360,1362,1365],{"class":39,"line":84},[37,1343,205],{"class":43},[37,1345,95],{"class":47},[37,1347,1348],{"class":98},"data",[37,1350,102],{"class":47},[37,1352,1353],{"class":98},"setData",[37,1355,108],{"class":47},[37,1357,111],{"class":43},[37,1359,115],{"class":114},[37,1361,118],{"class":47},[37,1363,1364],{"class":114},"computeExpensiveValue",[37,1366,1367],{"class":47},"())\n",[37,1369,1370],{"class":39,"line":89},[37,1371,310],{"class":47},[37,1373,1374],{"class":39,"line":127},[37,1375,62],{"emptyLinePlaceholder":61},[37,1377,1378],{"class":39,"line":132},[37,1379,1380],{"class":68},"\u002F\u002F PRODUCTION: lazy initializer — the function runs ONLY on the first render\n",[37,1382,1383,1385,1388],{"class":39,"line":138},[37,1384,193],{"class":43},[37,1386,1387],{"class":114}," GoodComponent",[37,1389,199],{"class":47},[37,1391,1392],{"class":39,"line":144},[37,1393,1394],{"class":68},"  \u002F\u002F useState accepts a function; calls it once, uses the return value.\n",[37,1396,1397,1399,1401,1403,1405,1407,1409,1411,1413,1415,1417],{"class":39,"line":150},[37,1398,205],{"class":43},[37,1400,95],{"class":47},[37,1402,1348],{"class":98},[37,1404,102],{"class":47},[37,1406,1353],{"class":98},[37,1408,108],{"class":47},[37,1410,111],{"class":43},[37,1412,115],{"class":114},[37,1414,920],{"class":47},[37,1416,923],{"class":43},[37,1418,757],{"class":47},[37,1420,1421,1423,1426,1428,1431,1434,1436,1439],{"class":39,"line":156},[37,1422,930],{"class":43},[37,1424,1425],{"class":98}," cached",[37,1427,768],{"class":43},[37,1429,1430],{"class":47}," localStorage.",[37,1432,1433],{"class":114},"getItem",[37,1435,118],{"class":47},[37,1437,1438],{"class":54},"'data'",[37,1440,124],{"class":47},[37,1442,1443,1445,1448,1451,1454,1457,1460,1463,1466,1469],{"class":39,"line":161},[37,1444,982],{"class":43},[37,1446,1447],{"class":47}," cached ",[37,1449,1450],{"class":43},"?",[37,1452,1453],{"class":98}," JSON",[37,1455,1456],{"class":47},".",[37,1458,1459],{"class":114},"parse",[37,1461,1462],{"class":47},"(cached) ",[37,1464,1465],{"class":43},":",[37,1467,1468],{"class":114}," computeExpensiveValue",[37,1470,1471],{"class":47},"()\n",[37,1473,1474],{"class":39,"line":167},[37,1475,1476],{"class":47},"  })\n",[37,1478,1479],{"class":39,"line":173},[37,1480,1481],{"class":68},"  \u002F\u002F The arrow function runs ONLY on mount. On subsequent renders, useState\n",[37,1483,1484],{"class":39,"line":179},[37,1485,1486],{"class":68},"  \u002F\u002F returns the current state without calling the initializer again.\n",[37,1488,1489],{"class":39,"line":185},[37,1490,310],{"class":47},[19,1492,1494],{"id":1493},"multiple-state-fields-separate-vs-object","Multiple State Fields: Separate vs Object",[24,1496,1498],{"filename":1497,"language":27},"state_field_patterns.js",[29,1499,1501],{"className":31,"code":1500,"language":27,"meta":33,"style":33},"\u002F\u002F PATTERN 1: separate useState calls — independent updates, simpler mental model\nconst [name, setName] = useState('')\nconst [email, setEmail] = useState('')\nconst [age, setAge] = useState(0)\n\u002F\u002F Each can update independently. No accidental overwrites of other fields.\n\n\u002F\u002F PATTERN 2: single object state — related fields that update together\nconst [form, setForm] = useState({ name: '', email: '', age: 0 })\n\u002F\u002F MUST use spread to merge — setForm({ name: 'X' }) ERASES email and age!\nfunction updateField(field, value) {\n  setForm(prev => ({ ...prev, [field]: value }))  \u002F\u002F ← spread preserves other fields\n}\n\n\u002F\u002F ANTI-PATTERN: replacing the object instead of merging\nsetForm({ name: 'Alice' })  \u002F\u002F email and age are now undefined! Object replaced.\n\n\u002F\u002F RULE OF THUMB:\n\u002F\u002F - Fields that update independently → separate useStates\n\u002F\u002F - Fields that update together \u002F represent one entity → single object (or useReducer, Ch 10)\n\u002F\u002F - For complex state logic with interdependencies → useReducer (Ch 10)\n",[15,1502,1503,1508,1535,1561,1587,1592,1596,1601,1639,1644,1664,1687,1691,1695,1700,1715,1719,1724,1729,1734],{"__ignoreMap":33},[37,1504,1505],{"class":39,"line":40},[37,1506,1507],{"class":68},"\u002F\u002F PATTERN 1: separate useState calls — independent updates, simpler mental model\n",[37,1509,1510,1512,1514,1517,1519,1522,1524,1526,1528,1530,1533],{"class":39,"line":58},[37,1511,92],{"class":43},[37,1513,95],{"class":47},[37,1515,1516],{"class":98},"name",[37,1518,102],{"class":47},[37,1520,1521],{"class":98},"setName",[37,1523,108],{"class":47},[37,1525,111],{"class":43},[37,1527,115],{"class":114},[37,1529,118],{"class":47},[37,1531,1532],{"class":54},"''",[37,1534,124],{"class":47},[37,1536,1537,1539,1541,1544,1546,1549,1551,1553,1555,1557,1559],{"class":39,"line":65},[37,1538,92],{"class":43},[37,1540,95],{"class":47},[37,1542,1543],{"class":98},"email",[37,1545,102],{"class":47},[37,1547,1548],{"class":98},"setEmail",[37,1550,108],{"class":47},[37,1552,111],{"class":43},[37,1554,115],{"class":114},[37,1556,118],{"class":47},[37,1558,1532],{"class":54},[37,1560,124],{"class":47},[37,1562,1563,1565,1567,1570,1572,1575,1577,1579,1581,1583,1585],{"class":39,"line":72},[37,1564,92],{"class":43},[37,1566,95],{"class":47},[37,1568,1569],{"class":98},"age",[37,1571,102],{"class":47},[37,1573,1574],{"class":98},"setAge",[37,1576,108],{"class":47},[37,1578,111],{"class":43},[37,1580,115],{"class":114},[37,1582,118],{"class":47},[37,1584,121],{"class":98},[37,1586,124],{"class":47},[37,1588,1589],{"class":39,"line":78},[37,1590,1591],{"class":68},"\u002F\u002F Each can update independently. No accidental overwrites of other fields.\n",[37,1593,1594],{"class":39,"line":84},[37,1595,62],{"emptyLinePlaceholder":61},[37,1597,1598],{"class":39,"line":89},[37,1599,1600],{"class":68},"\u002F\u002F PATTERN 2: single object state — related fields that update together\n",[37,1602,1603,1605,1607,1610,1612,1615,1617,1619,1621,1624,1626,1629,1631,1634,1636],{"class":39,"line":127},[37,1604,92],{"class":43},[37,1606,95],{"class":47},[37,1608,1609],{"class":98},"form",[37,1611,102],{"class":47},[37,1613,1614],{"class":98},"setForm",[37,1616,108],{"class":47},[37,1618,111],{"class":43},[37,1620,115],{"class":114},[37,1622,1623],{"class":47},"({ name: ",[37,1625,1532],{"class":54},[37,1627,1628],{"class":47},", email: ",[37,1630,1532],{"class":54},[37,1632,1633],{"class":47},", age: ",[37,1635,121],{"class":98},[37,1637,1638],{"class":47}," })\n",[37,1640,1641],{"class":39,"line":132},[37,1642,1643],{"class":68},"\u002F\u002F MUST use spread to merge — setForm({ name: 'X' }) ERASES email and age!\n",[37,1645,1646,1648,1651,1653,1656,1658,1661],{"class":39,"line":138},[37,1647,193],{"class":43},[37,1649,1650],{"class":114}," updateField",[37,1652,118],{"class":47},[37,1654,1655],{"class":491},"field",[37,1657,102],{"class":47},[37,1659,1660],{"class":491},"value",[37,1662,1663],{"class":47},") {\n",[37,1665,1666,1669,1671,1673,1675,1678,1681,1684],{"class":39,"line":144},[37,1667,1668],{"class":114},"  setForm",[37,1670,118],{"class":47},[37,1672,492],{"class":491},[37,1674,495],{"class":43},[37,1676,1677],{"class":47}," ({ ",[37,1679,1680],{"class":43},"...",[37,1682,1683],{"class":47},"prev, [field]: value }))  ",[37,1685,1686],{"class":68},"\u002F\u002F ← spread preserves other fields\n",[37,1688,1689],{"class":39,"line":150},[37,1690,310],{"class":47},[37,1692,1693],{"class":39,"line":156},[37,1694,62],{"emptyLinePlaceholder":61},[37,1696,1697],{"class":39,"line":161},[37,1698,1699],{"class":68},"\u002F\u002F ANTI-PATTERN: replacing the object instead of merging\n",[37,1701,1702,1704,1706,1709,1712],{"class":39,"line":167},[37,1703,1614],{"class":114},[37,1705,1623],{"class":47},[37,1707,1708],{"class":54},"'Alice'",[37,1710,1711],{"class":47}," })  ",[37,1713,1714],{"class":68},"\u002F\u002F email and age are now undefined! Object replaced.\n",[37,1716,1717],{"class":39,"line":173},[37,1718,62],{"emptyLinePlaceholder":61},[37,1720,1721],{"class":39,"line":179},[37,1722,1723],{"class":68},"\u002F\u002F RULE OF THUMB:\n",[37,1725,1726],{"class":39,"line":185},[37,1727,1728],{"class":68},"\u002F\u002F - Fields that update independently → separate useStates\n",[37,1730,1731],{"class":39,"line":190},[37,1732,1733],{"class":68},"\u002F\u002F - Fields that update together \u002F represent one entity → single object (or useReducer, Ch 10)\n",[37,1735,1736],{"class":39,"line":202},[37,1737,1738],{"class":68},"\u002F\u002F - For complex state logic with interdependencies → useReducer (Ch 10)\n",[19,1740,1742],{"id":1741},"anti-pattern-deriving-state-from-props","Anti-Pattern: Deriving State from Props",[24,1744,1746],{"filename":1745,"language":27},"anti_pattern_derived_state.js",[29,1747,1749],{"className":31,"code":1748,"language":27,"meta":33,"style":33},"\u002F\u002F ANTI-PATTERN: copying props into state and syncing manually\nfunction BadEmailInput({ initialEmail }) {\n  const [email, setEmail] = useState(initialEmail)\n  \u002F\u002F If initialEmail changes after mount, this state is STALE — useState only\n  \u002F\u002F reads the initial value once. Adding a useEffect to sync is an anti-pattern\n  \u002F\u002F that causes an extra render and can cause \"flashing\" of the old value.\n  useEffect(() => {\n    setEmail(initialEmail)  \u002F\u002F ← BAD: extra render, potential flicker\n  }, [initialEmail])\n  return \u003Cinput value={email} onChange={e => setEmail(e.target.value)} \u002F>\n}\n\n\u002F\u002F PRODUCTION: use the key prop to reset the component when the prop changes\nfunction GoodEmailInput({ initialEmail }) {\n  const [email, setEmail] = useState(initialEmail)\n  return \u003Cinput value={email} onChange={e => setEmail(e.target.value)} \u002F>\n}\n\u002F\u002F Parent usage: \u003CGoodEmailInput key={userId} initialEmail={user.email} \u002F>\n\u002F\u002F Changing key unmounts and remounts the component → state resets cleanly.\n\u002F\u002F No syncing effects, no extra renders, no flicker.\n",[15,1750,1751,1756,1770,1791,1796,1801,1806,1816,1827,1832,1868,1872,1876,1881,1894,1914,1942,1946,1951,1956],{"__ignoreMap":33},[37,1752,1753],{"class":39,"line":40},[37,1754,1755],{"class":68},"\u002F\u002F ANTI-PATTERN: copying props into state and syncing manually\n",[37,1757,1758,1760,1763,1765,1768],{"class":39,"line":58},[37,1759,193],{"class":43},[37,1761,1762],{"class":114}," BadEmailInput",[37,1764,603],{"class":47},[37,1766,1767],{"class":491},"initialEmail",[37,1769,609],{"class":47},[37,1771,1772,1774,1776,1778,1780,1782,1784,1786,1788],{"class":39,"line":65},[37,1773,205],{"class":43},[37,1775,95],{"class":47},[37,1777,1543],{"class":98},[37,1779,102],{"class":47},[37,1781,1548],{"class":98},[37,1783,108],{"class":47},[37,1785,111],{"class":43},[37,1787,115],{"class":114},[37,1789,1790],{"class":47},"(initialEmail)\n",[37,1792,1793],{"class":39,"line":72},[37,1794,1795],{"class":68},"  \u002F\u002F If initialEmail changes after mount, this state is STALE — useState only\n",[37,1797,1798],{"class":39,"line":78},[37,1799,1800],{"class":68},"  \u002F\u002F reads the initial value once. Adding a useEffect to sync is an anti-pattern\n",[37,1802,1803],{"class":39,"line":84},[37,1804,1805],{"class":68},"  \u002F\u002F that causes an extra render and can cause \"flashing\" of the old value.\n",[37,1807,1808,1810,1812,1814],{"class":39,"line":89},[37,1809,917],{"class":114},[37,1811,920],{"class":47},[37,1813,923],{"class":43},[37,1815,757],{"class":47},[37,1817,1818,1821,1824],{"class":39,"line":127},[37,1819,1820],{"class":114},"    setEmail",[37,1822,1823],{"class":47},"(initialEmail)  ",[37,1825,1826],{"class":68},"\u002F\u002F ← BAD: extra render, potential flicker\n",[37,1828,1829],{"class":39,"line":132},[37,1830,1831],{"class":47},"  }, [initialEmail])\n",[37,1833,1834,1836,1838,1841,1844,1846,1849,1852,1854,1857,1860,1862,1865],{"class":39,"line":138},[37,1835,284],{"class":43},[37,1837,287],{"class":47},[37,1839,1840],{"class":290},"input",[37,1842,1843],{"class":114}," value",[37,1845,111],{"class":43},[37,1847,1848],{"class":47},"{email} ",[37,1850,1851],{"class":114},"onChange",[37,1853,111],{"class":43},[37,1855,1856],{"class":47},"{",[37,1858,1859],{"class":491},"e",[37,1861,495],{"class":43},[37,1863,1864],{"class":114}," setEmail",[37,1866,1867],{"class":47},"(e.target.value)} \u002F>\n",[37,1869,1870],{"class":39,"line":144},[37,1871,310],{"class":47},[37,1873,1874],{"class":39,"line":150},[37,1875,62],{"emptyLinePlaceholder":61},[37,1877,1878],{"class":39,"line":156},[37,1879,1880],{"class":68},"\u002F\u002F PRODUCTION: use the key prop to reset the component when the prop changes\n",[37,1882,1883,1885,1888,1890,1892],{"class":39,"line":161},[37,1884,193],{"class":43},[37,1886,1887],{"class":114}," GoodEmailInput",[37,1889,603],{"class":47},[37,1891,1767],{"class":491},[37,1893,609],{"class":47},[37,1895,1896,1898,1900,1902,1904,1906,1908,1910,1912],{"class":39,"line":167},[37,1897,205],{"class":43},[37,1899,95],{"class":47},[37,1901,1543],{"class":98},[37,1903,102],{"class":47},[37,1905,1548],{"class":98},[37,1907,108],{"class":47},[37,1909,111],{"class":43},[37,1911,115],{"class":114},[37,1913,1790],{"class":47},[37,1915,1916,1918,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1940],{"class":39,"line":173},[37,1917,284],{"class":43},[37,1919,287],{"class":47},[37,1921,1840],{"class":290},[37,1923,1843],{"class":114},[37,1925,111],{"class":43},[37,1927,1848],{"class":47},[37,1929,1851],{"class":114},[37,1931,111],{"class":43},[37,1933,1856],{"class":47},[37,1935,1859],{"class":491},[37,1937,495],{"class":43},[37,1939,1864],{"class":114},[37,1941,1867],{"class":47},[37,1943,1944],{"class":39,"line":179},[37,1945,310],{"class":47},[37,1947,1948],{"class":39,"line":185},[37,1949,1950],{"class":68},"\u002F\u002F Parent usage: \u003CGoodEmailInput key={userId} initialEmail={user.email} \u002F>\n",[37,1952,1953],{"class":39,"line":190},[37,1954,1955],{"class":68},"\u002F\u002F Changing key unmounts and remounts the component → state resets cleanly.\n",[37,1957,1958],{"class":39,"line":202},[37,1959,1960],{"class":68},"\u002F\u002F No syncing effects, no extra renders, no flicker.\n",[19,1962,1964],{"id":1963},"tips-tricks","💡 Tips & Tricks",[24,1966,1968],{"filename":1967,"language":27},"tips.js",[29,1969,1971],{"className":31,"code":1970,"language":27,"meta":33,"style":33},"\u002F\u002F [Idiom] Use functional updates (prev => prev + 1) whenever the next state\n\u002F\u002F depends on the previous. This avoids stale closures and batch-update bugs.\n\n\u002F\u002F [Performance] Use lazy initialization useState(() => expensive()) for any\n\u002F\u002F initial value that involves computation, parsing, or I\u002FO. Runs once, not\n\u002F\u002F every render.\n\n\u002F\u002F [Debug] If state updates seem to \"not apply\" or only apply partially, check\n\u002F\u002F for direct-value updates that should be functional updates. Multiple\n\u002F\u002F setCount(count + 1) calls in the same handler all use the same snapshot.\n\n\u002F\u002F [Idiom] For related state that updates together, use a single object with\n\u002F\u002F spread: setForm(prev => ({ ...prev, [field]: value })). For complex logic,\n\u002F\u002F use useReducer (Ch 10) — the reducer centralizes all state transitions.\n\n\u002F\u002F [Idiom] To reset a component's state, change its key prop — React unmounts\n\u002F\u002F and remounts it. Cleaner than syncing state with useEffect.\n",[15,1972,1973,1978,1983,1987,1992,1997,2002,2006,2011,2016,2021,2025,2030,2035,2040,2044,2049],{"__ignoreMap":33},[37,1974,1975],{"class":39,"line":40},[37,1976,1977],{"class":68},"\u002F\u002F [Idiom] Use functional updates (prev => prev + 1) whenever the next state\n",[37,1979,1980],{"class":39,"line":58},[37,1981,1982],{"class":68},"\u002F\u002F depends on the previous. This avoids stale closures and batch-update bugs.\n",[37,1984,1985],{"class":39,"line":65},[37,1986,62],{"emptyLinePlaceholder":61},[37,1988,1989],{"class":39,"line":72},[37,1990,1991],{"class":68},"\u002F\u002F [Performance] Use lazy initialization useState(() => expensive()) for any\n",[37,1993,1994],{"class":39,"line":78},[37,1995,1996],{"class":68},"\u002F\u002F initial value that involves computation, parsing, or I\u002FO. Runs once, not\n",[37,1998,1999],{"class":39,"line":84},[37,2000,2001],{"class":68},"\u002F\u002F every render.\n",[37,2003,2004],{"class":39,"line":89},[37,2005,62],{"emptyLinePlaceholder":61},[37,2007,2008],{"class":39,"line":127},[37,2009,2010],{"class":68},"\u002F\u002F [Debug] If state updates seem to \"not apply\" or only apply partially, check\n",[37,2012,2013],{"class":39,"line":132},[37,2014,2015],{"class":68},"\u002F\u002F for direct-value updates that should be functional updates. Multiple\n",[37,2017,2018],{"class":39,"line":138},[37,2019,2020],{"class":68},"\u002F\u002F setCount(count + 1) calls in the same handler all use the same snapshot.\n",[37,2022,2023],{"class":39,"line":144},[37,2024,62],{"emptyLinePlaceholder":61},[37,2026,2027],{"class":39,"line":150},[37,2028,2029],{"class":68},"\u002F\u002F [Idiom] For related state that updates together, use a single object with\n",[37,2031,2032],{"class":39,"line":156},[37,2033,2034],{"class":68},"\u002F\u002F spread: setForm(prev => ({ ...prev, [field]: value })). For complex logic,\n",[37,2036,2037],{"class":39,"line":161},[37,2038,2039],{"class":68},"\u002F\u002F use useReducer (Ch 10) — the reducer centralizes all state transitions.\n",[37,2041,2042],{"class":39,"line":167},[37,2043,62],{"emptyLinePlaceholder":61},[37,2045,2046],{"class":39,"line":173},[37,2047,2048],{"class":68},"\u002F\u002F [Idiom] To reset a component's state, change its key prop — React unmounts\n",[37,2050,2051],{"class":39,"line":179},[37,2052,2053],{"class":68},"\u002F\u002F and remounts it. Cleaner than syncing state with useEffect.\n",[19,2055,2057],{"id":2056},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[24,2059,2061],{"filename":2060,"language":27},"edge_cases.js",[29,2062,2064],{"className":31,"code":2063,"language":27,"meta":33,"style":33},"\u002F\u002F [Gotcha] State is a SNAPSHOT, not a live reference. After setCount(5),\n\u002F\u002F `count` is still the old value until the next render. Accessing count\n\u002F\u002F immediately after setCount logs the stale value.\n\n\u002F\u002F [Gotcha] Object\u002Farray state requires a NEW reference to trigger re-render.\n\u002F\u002F setItems(items.push(newItem)) → BUG: push mutates the array in place,\n\u002F\u002F React sees the same reference → no re-render.\n\u002F\u002F FIX: setItems([...items, newItem]) — spread creates a new array reference.\n\n\u002F\u002F [Gotcha] useState with the SAME value (Object.is comparison) does NOT\n\u002F\u002F trigger a re-render. setCount(5) when count is already 5 → no-op, no render.\n\u002F\u002F But setCount({ ...count }) (new object with same content) → DOES re-render,\n\u002F\u002F because Object.is({}, {}) is false. Don't create new objects unless you mean it.\n\n\u002F\u002F [Gotcha] In React 17, state updates outside React event handlers (setTimeout,\n\u002F\u002F fetch callbacks) were NOT batched → each setX caused a separate render.\n\u002F\u002F React 18 batches ALL updates everywhere. If you relied on un-batched renders\n\u002F\u002F for sequencing, behavior changes on upgrade.\n\n\u002F\u002F [Gotcha] Calling a state setter during render (not in an event handler or\n\u002F\u002F effect) throws \"Cannot update a component while rendering a different component\"\n\u002F\u002F — but calling YOUR OWN setter during render IS allowed (it's the \"getDerivedState\n\u002F\u002F from props\" escape hatch). Use sparingly — it causes an immediate re-render.\n",[15,2065,2066,2071,2076,2081,2085,2090,2095,2100,2105,2109,2114,2119,2124,2129,2133,2138,2143,2148,2153,2157,2162,2167,2172],{"__ignoreMap":33},[37,2067,2068],{"class":39,"line":40},[37,2069,2070],{"class":68},"\u002F\u002F [Gotcha] State is a SNAPSHOT, not a live reference. After setCount(5),\n",[37,2072,2073],{"class":39,"line":58},[37,2074,2075],{"class":68},"\u002F\u002F `count` is still the old value until the next render. Accessing count\n",[37,2077,2078],{"class":39,"line":65},[37,2079,2080],{"class":68},"\u002F\u002F immediately after setCount logs the stale value.\n",[37,2082,2083],{"class":39,"line":72},[37,2084,62],{"emptyLinePlaceholder":61},[37,2086,2087],{"class":39,"line":78},[37,2088,2089],{"class":68},"\u002F\u002F [Gotcha] Object\u002Farray state requires a NEW reference to trigger re-render.\n",[37,2091,2092],{"class":39,"line":84},[37,2093,2094],{"class":68},"\u002F\u002F setItems(items.push(newItem)) → BUG: push mutates the array in place,\n",[37,2096,2097],{"class":39,"line":89},[37,2098,2099],{"class":68},"\u002F\u002F React sees the same reference → no re-render.\n",[37,2101,2102],{"class":39,"line":127},[37,2103,2104],{"class":68},"\u002F\u002F FIX: setItems([...items, newItem]) — spread creates a new array reference.\n",[37,2106,2107],{"class":39,"line":132},[37,2108,62],{"emptyLinePlaceholder":61},[37,2110,2111],{"class":39,"line":138},[37,2112,2113],{"class":68},"\u002F\u002F [Gotcha] useState with the SAME value (Object.is comparison) does NOT\n",[37,2115,2116],{"class":39,"line":144},[37,2117,2118],{"class":68},"\u002F\u002F trigger a re-render. setCount(5) when count is already 5 → no-op, no render.\n",[37,2120,2121],{"class":39,"line":150},[37,2122,2123],{"class":68},"\u002F\u002F But setCount({ ...count }) (new object with same content) → DOES re-render,\n",[37,2125,2126],{"class":39,"line":156},[37,2127,2128],{"class":68},"\u002F\u002F because Object.is({}, {}) is false. Don't create new objects unless you mean it.\n",[37,2130,2131],{"class":39,"line":161},[37,2132,62],{"emptyLinePlaceholder":61},[37,2134,2135],{"class":39,"line":167},[37,2136,2137],{"class":68},"\u002F\u002F [Gotcha] In React 17, state updates outside React event handlers (setTimeout,\n",[37,2139,2140],{"class":39,"line":173},[37,2141,2142],{"class":68},"\u002F\u002F fetch callbacks) were NOT batched → each setX caused a separate render.\n",[37,2144,2145],{"class":39,"line":179},[37,2146,2147],{"class":68},"\u002F\u002F React 18 batches ALL updates everywhere. If you relied on un-batched renders\n",[37,2149,2150],{"class":39,"line":185},[37,2151,2152],{"class":68},"\u002F\u002F for sequencing, behavior changes on upgrade.\n",[37,2154,2155],{"class":39,"line":190},[37,2156,62],{"emptyLinePlaceholder":61},[37,2158,2159],{"class":39,"line":202},[37,2160,2161],{"class":68},"\u002F\u002F [Gotcha] Calling a state setter during render (not in an event handler or\n",[37,2163,2164],{"class":39,"line":228},[37,2165,2166],{"class":68},"\u002F\u002F effect) throws \"Cannot update a component while rendering a different component\"\n",[37,2168,2169],{"class":39,"line":239},[37,2170,2171],{"class":68},"\u002F\u002F — but calling YOUR OWN setter during render IS allowed (it's the \"getDerivedState\n",[37,2173,2174],{"class":39,"line":260},[37,2175,2176],{"class":68},"\u002F\u002F from props\" escape hatch). Use sparingly — it causes an immediate re-render.\n",[19,2178,2180],{"id":2179},"spot-the-bug","🧠 Spot the Bug",[2182,2183,2184],"p",{},"A counter should increment by 3 when clicked, but it only goes up by 1:",[24,2186,2188],{"filename":2187,"language":27},"spot_the_bug.js",[29,2189,2191],{"className":31,"code":2190,"language":27,"meta":33,"style":33},"function TripleCounter() {\n  const [count, setCount] = useState(0)\n  function handleClick() {\n    setCount(count + 1)\n    setCount(count + 1)\n    setCount(count + 1)\n  }\n  return \u003Cbutton onClick={handleClick}>{count}\u003C\u002Fbutton>\n}\n",[15,2192,2193,2202,2226,2234,2246,2258,2270,2274,2292],{"__ignoreMap":33},[37,2194,2195,2197,2200],{"class":39,"line":40},[37,2196,193],{"class":43},[37,2198,2199],{"class":114}," TripleCounter",[37,2201,199],{"class":47},[37,2203,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222,2224],{"class":39,"line":58},[37,2205,205],{"class":43},[37,2207,95],{"class":47},[37,2209,99],{"class":98},[37,2211,102],{"class":47},[37,2213,105],{"class":98},[37,2215,108],{"class":47},[37,2217,111],{"class":43},[37,2219,115],{"class":114},[37,2221,118],{"class":47},[37,2223,121],{"class":98},[37,2225,124],{"class":47},[37,2227,2228,2230,2232],{"class":39,"line":65},[37,2229,231],{"class":43},[37,2231,234],{"class":114},[37,2233,199],{"class":47},[37,2235,2236,2238,2240,2242,2244],{"class":39,"line":72},[37,2237,242],{"class":114},[37,2239,245],{"class":47},[37,2241,248],{"class":43},[37,2243,251],{"class":98},[37,2245,124],{"class":47},[37,2247,2248,2250,2252,2254,2256],{"class":39,"line":78},[37,2249,242],{"class":114},[37,2251,245],{"class":47},[37,2253,248],{"class":43},[37,2255,251],{"class":98},[37,2257,124],{"class":47},[37,2259,2260,2262,2264,2266,2268],{"class":39,"line":84},[37,2261,242],{"class":114},[37,2263,245],{"class":47},[37,2265,248],{"class":43},[37,2267,251],{"class":98},[37,2269,124],{"class":47},[37,2271,2272],{"class":39,"line":89},[37,2273,278],{"class":47},[37,2275,2276,2278,2280,2282,2284,2286,2288,2290],{"class":39,"line":127},[37,2277,284],{"class":43},[37,2279,287],{"class":47},[37,2281,291],{"class":290},[37,2283,294],{"class":114},[37,2285,111],{"class":43},[37,2287,299],{"class":47},[37,2289,291],{"class":290},[37,2291,304],{"class":47},[37,2293,2294],{"class":39,"line":132},[37,2295,310],{"class":47},[2297,2298,2299,2303,2336,2347,2415],"details",{},[2300,2301,2302],"summary",{},"Answer",[2182,2304,2305,2306,2309,2310,2312,2313,2317,2318,2321,2322,2324,2325,2328,2329,2332,2333,1456],{},"All three ",[15,2307,2308],{},"setCount(count + 1)"," calls reference ",[15,2311,99],{}," from the ",[2314,2315,2316],"strong",{},"same render snapshot",". React batches the three updates, but each one computes ",[15,2319,2320],{},"count + 1"," using the original ",[15,2323,99],{}," value (0), so all three set state to ",[15,2326,2327],{},"1"," — net result: ",[15,2330,2331],{},"+1",", not ",[15,2334,2335],{},"+3",[2182,2337,2338,2341,2342,2346],{},[2314,2339,2340],{},"Fix",": use the functional updater form, which receives the ",[2343,2344,2345],"em",{},"latest"," queued state:",[29,2348,2350],{"className":31,"code":2349,"language":27,"meta":33,"style":33},"setCount(prev => prev + 1)  \u002F\u002F prev = 0 → sets to 1\nsetCount(prev => prev + 1)  \u002F\u002F prev = 1 → sets to 2\nsetCount(prev => prev + 1)  \u002F\u002F prev = 2 → sets to 3\n",[15,2351,2352,2373,2394],{"__ignoreMap":33},[37,2353,2354,2356,2358,2360,2362,2364,2366,2368,2370],{"class":39,"line":40},[37,2355,105],{"class":114},[37,2357,118],{"class":47},[37,2359,492],{"class":491},[37,2361,495],{"class":43},[37,2363,498],{"class":47},[37,2365,248],{"class":43},[37,2367,251],{"class":98},[37,2369,254],{"class":47},[37,2371,2372],{"class":68},"\u002F\u002F prev = 0 → sets to 1\n",[37,2374,2375,2377,2379,2381,2383,2385,2387,2389,2391],{"class":39,"line":58},[37,2376,105],{"class":114},[37,2378,118],{"class":47},[37,2380,492],{"class":491},[37,2382,495],{"class":43},[37,2384,498],{"class":47},[37,2386,248],{"class":43},[37,2388,251],{"class":98},[37,2390,254],{"class":47},[37,2392,2393],{"class":68},"\u002F\u002F prev = 1 → sets to 2\n",[37,2395,2396,2398,2400,2402,2404,2406,2408,2410,2412],{"class":39,"line":65},[37,2397,105],{"class":114},[37,2399,118],{"class":47},[37,2401,492],{"class":491},[37,2403,495],{"class":43},[37,2405,498],{"class":47},[37,2407,248],{"class":43},[37,2409,251],{"class":98},[37,2411,254],{"class":47},[37,2413,2414],{"class":68},"\u002F\u002F prev = 2 → sets to 3\n",[2182,2416,2417,2418,2420],{},"Each updater builds on the result of the previous one, giving the correct ",[15,2419,2335],{}," result.",[19,2422,2424],{"id":2423},"key-takeaways","Key Takeaways",[24,2426,2428],{"filename":2427,"language":27},"key_takeaways.js",[29,2429,2431],{"className":31,"code":2430,"language":27,"meta":33,"style":33},"\u002F\u002F 1. State is a SNAPSHOT, not a live reference. `count` doesn't update until\n\u002F\u002F    the next render. Accessing it immediately after setCount gives the old value.\n\n\u002F\u002F 2. Use functional updates (prev => prev + 1) when the next state depends on\n\u002F\u002F    the previous. Direct-value updates (count + 1) use the stale snapshot.\n\n\u002F\u002F 3. React 18 batches ALL state updates (event handlers, timeouts, promises).\n\u002F\u002F    Multiple setState calls in one handler → ONE re-render.\n\n\u002F\u002F 4. Lazy initialization: useState(() => expensive()) runs only on mount.\n\u002F\u002F    Without the arrow function, the initial value computes on EVERY render.\n\n\u002F\u002F 5. Object\u002Farray state needs a NEW reference to trigger re-render:\n\u002F\u002F    setItems([...items, newItem]) — NOT items.push(newItem) (in-place mutation).\n\n\u002F\u002F 6. Don't derive state from props with useEffect + setState. Use the key prop\n\u002F\u002F    to reset component state when a prop changes — cleaner, no extra render.\n",[15,2432,2433,2438,2443,2447,2452,2457,2461,2466,2471,2475,2480,2485,2489,2494,2499,2503,2508],{"__ignoreMap":33},[37,2434,2435],{"class":39,"line":40},[37,2436,2437],{"class":68},"\u002F\u002F 1. State is a SNAPSHOT, not a live reference. `count` doesn't update until\n",[37,2439,2440],{"class":39,"line":58},[37,2441,2442],{"class":68},"\u002F\u002F    the next render. Accessing it immediately after setCount gives the old value.\n",[37,2444,2445],{"class":39,"line":65},[37,2446,62],{"emptyLinePlaceholder":61},[37,2448,2449],{"class":39,"line":72},[37,2450,2451],{"class":68},"\u002F\u002F 2. Use functional updates (prev => prev + 1) when the next state depends on\n",[37,2453,2454],{"class":39,"line":78},[37,2455,2456],{"class":68},"\u002F\u002F    the previous. Direct-value updates (count + 1) use the stale snapshot.\n",[37,2458,2459],{"class":39,"line":84},[37,2460,62],{"emptyLinePlaceholder":61},[37,2462,2463],{"class":39,"line":89},[37,2464,2465],{"class":68},"\u002F\u002F 3. React 18 batches ALL state updates (event handlers, timeouts, promises).\n",[37,2467,2468],{"class":39,"line":127},[37,2469,2470],{"class":68},"\u002F\u002F    Multiple setState calls in one handler → ONE re-render.\n",[37,2472,2473],{"class":39,"line":132},[37,2474,62],{"emptyLinePlaceholder":61},[37,2476,2477],{"class":39,"line":138},[37,2478,2479],{"class":68},"\u002F\u002F 4. Lazy initialization: useState(() => expensive()) runs only on mount.\n",[37,2481,2482],{"class":39,"line":144},[37,2483,2484],{"class":68},"\u002F\u002F    Without the arrow function, the initial value computes on EVERY render.\n",[37,2486,2487],{"class":39,"line":150},[37,2488,62],{"emptyLinePlaceholder":61},[37,2490,2491],{"class":39,"line":156},[37,2492,2493],{"class":68},"\u002F\u002F 5. Object\u002Farray state needs a NEW reference to trigger re-render:\n",[37,2495,2496],{"class":39,"line":161},[37,2497,2498],{"class":68},"\u002F\u002F    setItems([...items, newItem]) — NOT items.push(newItem) (in-place mutation).\n",[37,2500,2501],{"class":39,"line":167},[37,2502,62],{"emptyLinePlaceholder":61},[37,2504,2505],{"class":39,"line":173},[37,2506,2507],{"class":68},"\u002F\u002F 6. Don't derive state from props with useEffect + setState. Use the key prop\n",[37,2509,2510],{"class":39,"line":179},[37,2511,2512],{"class":68},"\u002F\u002F    to reset component state when a prop changes — cleaner, no extra render.\n",[2514,2515,2516],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":33,"searchDepth":58,"depth":58,"links":2518},[2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529],{"id":21,"depth":58,"text":22},{"id":313,"depth":58,"text":314},{"id":570,"depth":58,"text":571},{"id":861,"depth":58,"text":862},{"id":1301,"depth":58,"text":1302},{"id":1493,"depth":58,"text":1494},{"id":1741,"depth":58,"text":1742},{"id":1963,"depth":58,"text":1964},{"id":2056,"depth":58,"text":2057},{"id":2179,"depth":58,"text":2180},{"id":2423,"depth":58,"text":2424},"useState mechanics, batch updates, functional updates vs direct values, stale closures, lazy initialization, React 18 automatic batching, and anti-patterns for derived state. Code-first reference for mid-to-senior React engineers.","md",{},"\u002Freact\u002F04-state-and-usestate",{"title":5,"description":2530},"react\u002F04-state-and-usestate","CoyxUD-D2boBekDP0fWp5sFqU4XV__Gpv97nWrytmWI",1789924652004]