[{"data":1,"prerenderedAt":5952},["ShallowReactive",2],{"page-\u002Freact\u002F03-components-and-props":3},{"id":4,"title":5,"body":6,"description":5945,"extension":5946,"meta":5947,"navigation":58,"path":5948,"seo":5949,"stem":5950,"__hash__":5951},"content\u002Freact\u002F03-components-and-props.md","03 — Components & Props",{"type":7,"value":8,"toc":5901},"minimark",[9,13,18,242,246,355,359,551,555,805,812,1001,1012,1203,1207,1347,1351,1502,1506,1510,1681,1685,1952,1962,2084,2092,2266,2272,2516,2520,2524,2749,2756,2966,2973,3288,3292,3994,3998,4002,4255,4259,4373,4377,4520,4524,5133,5137,5284,5288,5449,5453,5456,5583,5728,5732,5897],[10,11,5],"h1",{"id":12},"_03-components-props",[14,15,17],"h2",{"id":16},"function-component-anatomy","Function Component Anatomy",[19,20,23],"code-wrapper",{"filename":21,"language":22},"function_component_anatomy.js","javascript",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F A function component is a pure function: props in, JSX (or null) out.\n\u002F\u002F PascalCase is MANDATORY — JSX treats lowercase-first tags as host DOM elements.\n\u002F\u002F `\u003Cusercard \u002F>` → React renders an unknown HTML \u003Cusercard>, NOT your component.\n\nfunction UserCard({ name, title, avatarUrl }) {\n  \u002F\u002F No lifecycle, no instance, no `this`.\n  \u002F\u002F React calls this function whenever props OR state in the subtree change.\n  return (\n    \u003Cdiv className=\"user-card\">\n      \u003Cimg src={avatarUrl} alt={`${name}'s avatar`} \u002F>\n      \u003Ch3>{name}\u003C\u002Fh3>\n      \u003Cp>{title}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  )\n}\n\nexport default UserCard\n","",[30,31,32,41,47,53,60,93,99,105,114,137,173,188,203,213,219,225,230],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","\u002F\u002F A function component is a pure function: props in, JSX (or null) out.\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"\u002F\u002F PascalCase is MANDATORY — JSX treats lowercase-first tags as host DOM elements.\n",[33,48,50],{"class":35,"line":49},3,[33,51,52],{"class":39},"\u002F\u002F `\u003Cusercard \u002F>` → React renders an unknown HTML \u003Cusercard>, NOT your component.\n",[33,54,56],{"class":35,"line":55},4,[33,57,59],{"emptyLinePlaceholder":58},true,"\n",[33,61,63,67,71,75,79,82,85,87,90],{"class":35,"line":62},5,[33,64,66],{"class":65},"svdQ7","function",[33,68,70],{"class":69},"sIsaT"," UserCard",[33,72,74],{"class":73},"ssxIu","({ ",[33,76,78],{"class":77},"sCrzJ","name",[33,80,81],{"class":73},", ",[33,83,84],{"class":77},"title",[33,86,81],{"class":73},[33,88,89],{"class":77},"avatarUrl",[33,91,92],{"class":73}," }) {\n",[33,94,96],{"class":35,"line":95},6,[33,97,98],{"class":39},"  \u002F\u002F No lifecycle, no instance, no `this`.\n",[33,100,102],{"class":35,"line":101},7,[33,103,104],{"class":39},"  \u002F\u002F React calls this function whenever props OR state in the subtree change.\n",[33,106,108,111],{"class":35,"line":107},8,[33,109,110],{"class":65},"  return",[33,112,113],{"class":73}," (\n",[33,115,117,120,124,127,130,134],{"class":35,"line":116},9,[33,118,119],{"class":73},"    \u003C",[33,121,123],{"class":122},"sk71V","div",[33,125,126],{"class":69}," className",[33,128,129],{"class":65},"=",[33,131,133],{"class":132},"sJ6F3","\"user-card\"",[33,135,136],{"class":73},">\n",[33,138,140,143,146,149,151,154,157,159,162,165,167,170],{"class":35,"line":139},10,[33,141,142],{"class":73},"      \u003C",[33,144,145],{"class":122},"img",[33,147,148],{"class":69}," src",[33,150,129],{"class":65},[33,152,153],{"class":73},"{avatarUrl} ",[33,155,156],{"class":69},"alt",[33,158,129],{"class":65},[33,160,161],{"class":73},"{",[33,163,164],{"class":132},"`${",[33,166,78],{"class":73},[33,168,169],{"class":132},"}'s avatar`",[33,171,172],{"class":73},"} \u002F>\n",[33,174,176,178,181,184,186],{"class":35,"line":175},11,[33,177,142],{"class":73},[33,179,180],{"class":122},"h3",[33,182,183],{"class":73},">{name}\u003C\u002F",[33,185,180],{"class":122},[33,187,136],{"class":73},[33,189,191,193,196,199,201],{"class":35,"line":190},12,[33,192,142],{"class":73},[33,194,195],{"class":122},"p",[33,197,198],{"class":73},">{title}\u003C\u002F",[33,200,195],{"class":122},[33,202,136],{"class":73},[33,204,206,209,211],{"class":35,"line":205},13,[33,207,208],{"class":73},"    \u003C\u002F",[33,210,123],{"class":122},[33,212,136],{"class":73},[33,214,216],{"class":35,"line":215},14,[33,217,218],{"class":73},"  )\n",[33,220,222],{"class":35,"line":221},15,[33,223,224],{"class":73},"}\n",[33,226,228],{"class":35,"line":227},16,[33,229,59],{"emptyLinePlaceholder":58},[33,231,233,236,239],{"class":35,"line":232},17,[33,234,235],{"class":65},"export",[33,237,238],{"class":65}," default",[33,240,241],{"class":73}," UserCard\n",[180,243,245],{"id":244},"arrow-function-form-equivalent-not-identical","Arrow Function Form — Equivalent, Not Identical",[19,247,249],{"filename":248,"language":22},"arrow_vs_declaration.js",[24,250,252],{"className":26,"code":251,"language":22,"meta":28,"style":28},"\u002F\u002F Declaration form — hoisted; can be referenced before its definition in the module.\nfunction Button({ label }) { return \u003Cbutton>{label}\u003C\u002Fbutton> }\n\n\u002F\u002F Arrow form — not hoisted; assigned to a const. Identical behavior to React.\nconst Button = ({ label }) => \u003Cbutton>{label}\u003C\u002Fbutton>\n\n\u002F\u002F DIFFERENCE THAT MATTERS: arrow functions have no own `arguments`, `this`, or\n\u002F\u002F `new.target`. Neither matters for function components today, but tooling like\n\u002F\u002F some older HOCs and certain decorators rely on `this`-binding — declaration\n\u002F\u002F form is safer if you're unsure. Most teams pick one via lint rule and move on.\n",[30,253,254,259,291,295,300,331,335,340,345,350],{"__ignoreMap":28},[33,255,256],{"class":35,"line":36},[33,257,258],{"class":39},"\u002F\u002F Declaration form — hoisted; can be referenced before its definition in the module.\n",[33,260,261,263,266,268,271,274,277,280,283,286,288],{"class":35,"line":43},[33,262,66],{"class":65},[33,264,265],{"class":69}," Button",[33,267,74],{"class":73},[33,269,270],{"class":77},"label",[33,272,273],{"class":73}," }) { ",[33,275,276],{"class":65},"return",[33,278,279],{"class":73}," \u003C",[33,281,282],{"class":122},"button",[33,284,285],{"class":73},">{label}\u003C\u002F",[33,287,282],{"class":122},[33,289,290],{"class":73},"> }\n",[33,292,293],{"class":35,"line":49},[33,294,59],{"emptyLinePlaceholder":58},[33,296,297],{"class":35,"line":55},[33,298,299],{"class":39},"\u002F\u002F Arrow form — not hoisted; assigned to a const. Identical behavior to React.\n",[33,301,302,305,307,310,313,315,318,321,323,325,327,329],{"class":35,"line":62},[33,303,304],{"class":65},"const",[33,306,265],{"class":69},[33,308,309],{"class":65}," =",[33,311,312],{"class":73}," ({ ",[33,314,270],{"class":77},[33,316,317],{"class":73}," }) ",[33,319,320],{"class":65},"=>",[33,322,279],{"class":73},[33,324,282],{"class":122},[33,326,285],{"class":73},[33,328,282],{"class":122},[33,330,136],{"class":73},[33,332,333],{"class":35,"line":95},[33,334,59],{"emptyLinePlaceholder":58},[33,336,337],{"class":35,"line":101},[33,338,339],{"class":39},"\u002F\u002F DIFFERENCE THAT MATTERS: arrow functions have no own `arguments`, `this`, or\n",[33,341,342],{"class":35,"line":107},[33,343,344],{"class":39},"\u002F\u002F `new.target`. Neither matters for function components today, but tooling like\n",[33,346,347],{"class":35,"line":116},[33,348,349],{"class":39},"\u002F\u002F some older HOCs and certain decorators rely on `this`-binding — declaration\n",[33,351,352],{"class":35,"line":139},[33,353,354],{"class":39},"\u002F\u002F form is safer if you're unsure. Most teams pick one via lint rule and move on.\n",[180,356,358],{"id":357},"return-value-rules","Return Value Rules",[19,360,362],{"filename":361,"language":22},"return_value_rules.js",[24,363,365],{"className":26,"code":364,"language":22,"meta":28,"style":28},"\u002F\u002F Valid return values:\n\u002F\u002F   1. A single JSX element (most common)\n\u002F\u002F   2. null (render nothing — no DOM node produced)\n\u002F\u002F   3. An array of elements (each MUST have a stable `key` prop)\n\u002F\u002F   4. A string or number (rendered as a text node)\n\u002F\u002F   5. A Fragment (\u003C>\u003C\u002F> or \u003CReact.Fragment>) — groups without a wrapper DOM node\n\u002F\u002F   6. A Portal (ReactDOM.createPortal — renders into a different DOM subtree, Ch 18)\n\nfunction Conditional({ show }) {\n  if (!show) return null  \u002F\u002F produces zero DOM nodes — not even an empty \u003Cdiv>\n  return \u003Cp>Visible\u003C\u002Fp>\n}\n\n\u002F\u002F INVALID: returning multiple sibling elements without a wrapping Fragment.\n\u002F\u002F function Broken() { return \u003Ch1>A\u003C\u002Fh1> \u003Cp>B\u003C\u002Fp> }  \u002F\u002F SyntaxError \u002F undefined return\n\u002F\u002F CORRECT: Fragment groups them without polluting the DOM with a wrapper \u003Cdiv>.\nfunction Fixed() {\n  return (\n    \u003C>\n      \u003Ch1>A\u003C\u002Fh1>\n      \u003Cp>B\u003C\u002Fp>\n    \u003C\u002F>\n  )\n}\n",[30,366,367,372,377,382,387,392,397,402,406,420,443,458,462,466,471,479,484,494,501,507,521,535,541,546],{"__ignoreMap":28},[33,368,369],{"class":35,"line":36},[33,370,371],{"class":39},"\u002F\u002F Valid return values:\n",[33,373,374],{"class":35,"line":43},[33,375,376],{"class":39},"\u002F\u002F   1. A single JSX element (most common)\n",[33,378,379],{"class":35,"line":49},[33,380,381],{"class":39},"\u002F\u002F   2. null (render nothing — no DOM node produced)\n",[33,383,384],{"class":35,"line":55},[33,385,386],{"class":39},"\u002F\u002F   3. An array of elements (each MUST have a stable `key` prop)\n",[33,388,389],{"class":35,"line":62},[33,390,391],{"class":39},"\u002F\u002F   4. A string or number (rendered as a text node)\n",[33,393,394],{"class":35,"line":95},[33,395,396],{"class":39},"\u002F\u002F   5. A Fragment (\u003C>\u003C\u002F> or \u003CReact.Fragment>) — groups without a wrapper DOM node\n",[33,398,399],{"class":35,"line":101},[33,400,401],{"class":39},"\u002F\u002F   6. A Portal (ReactDOM.createPortal — renders into a different DOM subtree, Ch 18)\n",[33,403,404],{"class":35,"line":107},[33,405,59],{"emptyLinePlaceholder":58},[33,407,408,410,413,415,418],{"class":35,"line":116},[33,409,66],{"class":65},[33,411,412],{"class":69}," Conditional",[33,414,74],{"class":73},[33,416,417],{"class":77},"show",[33,419,92],{"class":73},[33,421,422,425,428,431,434,436,440],{"class":35,"line":139},[33,423,424],{"class":65},"  if",[33,426,427],{"class":73}," (",[33,429,430],{"class":65},"!",[33,432,433],{"class":73},"show) ",[33,435,276],{"class":65},[33,437,439],{"class":438},"snvgF"," null",[33,441,442],{"class":39},"  \u002F\u002F produces zero DOM nodes — not even an empty \u003Cdiv>\n",[33,444,445,447,449,451,454,456],{"class":35,"line":175},[33,446,110],{"class":65},[33,448,279],{"class":73},[33,450,195],{"class":122},[33,452,453],{"class":73},">Visible\u003C\u002F",[33,455,195],{"class":122},[33,457,136],{"class":73},[33,459,460],{"class":35,"line":190},[33,461,224],{"class":73},[33,463,464],{"class":35,"line":205},[33,465,59],{"emptyLinePlaceholder":58},[33,467,468],{"class":35,"line":215},[33,469,470],{"class":39},"\u002F\u002F INVALID: returning multiple sibling elements without a wrapping Fragment.\n",[33,472,473,476],{"class":35,"line":221},[33,474,475],{"class":39},"\u002F\u002F function Broken() { return \u003Ch1>A\u003C\u002Fh1> \u003Cp>B\u003C\u002Fp> }",[33,477,478],{"class":39},"  \u002F\u002F SyntaxError \u002F undefined return\n",[33,480,481],{"class":35,"line":227},[33,482,483],{"class":39},"\u002F\u002F CORRECT: Fragment groups them without polluting the DOM with a wrapper \u003Cdiv>.\n",[33,485,486,488,491],{"class":35,"line":232},[33,487,66],{"class":65},[33,489,490],{"class":69}," Fixed",[33,492,493],{"class":73},"() {\n",[33,495,497,499],{"class":35,"line":496},18,[33,498,110],{"class":65},[33,500,113],{"class":73},[33,502,504],{"class":35,"line":503},19,[33,505,506],{"class":73},"    \u003C>\n",[33,508,510,512,514,517,519],{"class":35,"line":509},20,[33,511,142],{"class":73},[33,513,10],{"class":122},[33,515,516],{"class":73},">A\u003C\u002F",[33,518,10],{"class":122},[33,520,136],{"class":73},[33,522,524,526,528,531,533],{"class":35,"line":523},21,[33,525,142],{"class":73},[33,527,195],{"class":122},[33,529,530],{"class":73},">B\u003C\u002F",[33,532,195],{"class":122},[33,534,136],{"class":73},[33,536,538],{"class":35,"line":537},22,[33,539,540],{"class":73},"    \u003C\u002F>\n",[33,542,544],{"class":35,"line":543},23,[33,545,218],{"class":73},[33,547,549],{"class":35,"line":548},24,[33,550,224],{"class":73},[14,552,554],{"id":553},"props-destructuring-the-signature-is-the-documentation","Props Destructuring — The Signature IS the Documentation",[19,556,558],{"filename":557,"language":22},"destructuring.js",[24,559,561],{"className":26,"code":560,"language":22,"meta":28,"style":28},"\u002F\u002F ANTI-PATTERN: props object dotting — you must read the whole body to know the API.\nfunction OrderSummary(props) {\n  return \u003Cp>{props.itemCount} items · ${props.total.toFixed(2)}\u003C\u002Fp>\n}\n\n\u002F\u002F IDIOMATIC: destructure in the signature. The parameter list IS the public API.\nfunction OrderSummary({ itemCount, total }) {\n  return \u003Cp>{itemCount} items · ${total.toFixed(2)}\u003C\u002Fp>\n}\n\n\u002F\u002F Rename during destructuring — useful when the internal name differs from the prop name.\nfunction Badge({ count: unreadCount = 0 }) {\n  return \u003Cspan>{unreadCount}\u003C\u002Fspan>  \u002F\u002F prop is `count`, internal name is `unreadCount`\n}\n\n\u002F\u002F Rest props — collect everything you don't explicitly consume, forward downstream.\nfunction Input({ label, ...rest }) {\n  return (\n    \u003Clabel>\n      {label}\n      \u003Cinput {...rest} \u002F>  \u002F\u002F forwards type, value, onChange, placeholder, etc.\n    \u003C\u002Flabel>\n  )\n}\n",[30,562,563,568,584,610,614,618,623,641,664,668,672,677,702,721,725,729,734,755,761,769,774,789,797,801],{"__ignoreMap":28},[33,564,565],{"class":35,"line":36},[33,566,567],{"class":39},"\u002F\u002F ANTI-PATTERN: props object dotting — you must read the whole body to know the API.\n",[33,569,570,572,575,578,581],{"class":35,"line":43},[33,571,66],{"class":65},[33,573,574],{"class":69}," OrderSummary",[33,576,577],{"class":73},"(",[33,579,580],{"class":77},"props",[33,582,583],{"class":73},") {\n",[33,585,586,588,590,592,595,598,600,603,606,608],{"class":35,"line":49},[33,587,110],{"class":65},[33,589,279],{"class":73},[33,591,195],{"class":122},[33,593,594],{"class":73},">{props.itemCount} items · ${props.total.",[33,596,597],{"class":69},"toFixed",[33,599,577],{"class":73},[33,601,602],{"class":438},"2",[33,604,605],{"class":73},")}\u003C\u002F",[33,607,195],{"class":122},[33,609,136],{"class":73},[33,611,612],{"class":35,"line":55},[33,613,224],{"class":73},[33,615,616],{"class":35,"line":62},[33,617,59],{"emptyLinePlaceholder":58},[33,619,620],{"class":35,"line":95},[33,621,622],{"class":39},"\u002F\u002F IDIOMATIC: destructure in the signature. The parameter list IS the public API.\n",[33,624,625,627,629,631,634,636,639],{"class":35,"line":101},[33,626,66],{"class":65},[33,628,574],{"class":69},[33,630,74],{"class":73},[33,632,633],{"class":77},"itemCount",[33,635,81],{"class":73},[33,637,638],{"class":77},"total",[33,640,92],{"class":73},[33,642,643,645,647,649,652,654,656,658,660,662],{"class":35,"line":107},[33,644,110],{"class":65},[33,646,279],{"class":73},[33,648,195],{"class":122},[33,650,651],{"class":73},">{itemCount} items · ${total.",[33,653,597],{"class":69},[33,655,577],{"class":73},[33,657,602],{"class":438},[33,659,605],{"class":73},[33,661,195],{"class":122},[33,663,136],{"class":73},[33,665,666],{"class":35,"line":116},[33,667,224],{"class":73},[33,669,670],{"class":35,"line":139},[33,671,59],{"emptyLinePlaceholder":58},[33,673,674],{"class":35,"line":175},[33,675,676],{"class":39},"\u002F\u002F Rename during destructuring — useful when the internal name differs from the prop name.\n",[33,678,679,681,684,686,689,692,695,697,700],{"class":35,"line":190},[33,680,66],{"class":65},[33,682,683],{"class":69}," Badge",[33,685,74],{"class":73},[33,687,688],{"class":77},"count",[33,690,691],{"class":73},": ",[33,693,694],{"class":77},"unreadCount",[33,696,309],{"class":65},[33,698,699],{"class":438}," 0",[33,701,92],{"class":73},[33,703,704,706,708,710,713,715,718],{"class":35,"line":205},[33,705,110],{"class":65},[33,707,279],{"class":73},[33,709,33],{"class":122},[33,711,712],{"class":73},">{unreadCount}\u003C\u002F",[33,714,33],{"class":122},[33,716,717],{"class":73},">  ",[33,719,720],{"class":39},"\u002F\u002F prop is `count`, internal name is `unreadCount`\n",[33,722,723],{"class":35,"line":215},[33,724,224],{"class":73},[33,726,727],{"class":35,"line":221},[33,728,59],{"emptyLinePlaceholder":58},[33,730,731],{"class":35,"line":227},[33,732,733],{"class":39},"\u002F\u002F Rest props — collect everything you don't explicitly consume, forward downstream.\n",[33,735,736,738,741,743,745,747,750,753],{"class":35,"line":232},[33,737,66],{"class":65},[33,739,740],{"class":69}," Input",[33,742,74],{"class":73},[33,744,270],{"class":77},[33,746,81],{"class":73},[33,748,749],{"class":65},"...",[33,751,752],{"class":77},"rest",[33,754,92],{"class":73},[33,756,757,759],{"class":35,"line":496},[33,758,110],{"class":65},[33,760,113],{"class":73},[33,762,763,765,767],{"class":35,"line":503},[33,764,119],{"class":73},[33,766,270],{"class":122},[33,768,136],{"class":73},[33,770,771],{"class":35,"line":509},[33,772,773],{"class":73},"      {label}\n",[33,775,776,778,781,784,786],{"class":35,"line":523},[33,777,142],{"class":73},[33,779,780],{"class":122},"input",[33,782,783],{"class":73}," {",[33,785,749],{"class":65},[33,787,788],{"class":73},"rest} \u002F>  \u002F\u002F forwards type, value, onChange, placeholder, etc.\n",[33,790,791,793,795],{"class":35,"line":537},[33,792,208],{"class":73},[33,794,270],{"class":122},[33,796,136],{"class":73},[33,798,799],{"class":35,"line":543},[33,800,218],{"class":73},[33,802,803],{"class":35,"line":548},[33,804,224],{"class":73},[180,806,808,809],{"id":807},"destructuring-defaults-the-modern-replacement-for-defaultprops","Destructuring Defaults — The Modern Replacement for ",[30,810,811],{},"defaultProps",[19,813,815],{"filename":814,"language":22},"default_values.js",[24,816,818],{"className":26,"code":817,"language":22,"meta":28,"style":28},"\u002F\u002F ES2015 destructuring defaults — the supported, forward-compatible pattern.\n\u002F\u002F `defaultProps` on function components was deprecated in React 18.3 and logs\n\u002F\u002F a warning; default parameters are identical at runtime and have no deprecation path.\n\nfunction Button({ label, variant = 'primary', disabled = false, onClick }) {\n  return (\n    \u003Cbutton className={`btn btn--${variant}`} disabled={disabled} onClick={onClick}>\n      {label}\n    \u003C\u002Fbutton>\n  )\n}\n\n\u003CButton label=\"Save\" onClick={handleSave} \u002F>              \u002F\u002F variant='primary'\n\u003CButton label=\"Delete\" variant=\"danger\" onClick={fn} \u002F>   \u002F\u002F variant='danger'\n",[30,819,820,825,830,835,839,876,882,919,923,931,935,939,943,970],{"__ignoreMap":28},[33,821,822],{"class":35,"line":36},[33,823,824],{"class":39},"\u002F\u002F ES2015 destructuring defaults — the supported, forward-compatible pattern.\n",[33,826,827],{"class":35,"line":43},[33,828,829],{"class":39},"\u002F\u002F `defaultProps` on function components was deprecated in React 18.3 and logs\n",[33,831,832],{"class":35,"line":49},[33,833,834],{"class":39},"\u002F\u002F a warning; default parameters are identical at runtime and have no deprecation path.\n",[33,836,837],{"class":35,"line":55},[33,838,59],{"emptyLinePlaceholder":58},[33,840,841,843,845,847,849,851,854,856,859,861,864,866,869,871,874],{"class":35,"line":62},[33,842,66],{"class":65},[33,844,265],{"class":69},[33,846,74],{"class":73},[33,848,270],{"class":77},[33,850,81],{"class":73},[33,852,853],{"class":77},"variant",[33,855,309],{"class":65},[33,857,858],{"class":132}," 'primary'",[33,860,81],{"class":73},[33,862,863],{"class":77},"disabled",[33,865,309],{"class":65},[33,867,868],{"class":438}," false",[33,870,81],{"class":73},[33,872,873],{"class":77},"onClick",[33,875,92],{"class":73},[33,877,878,880],{"class":35,"line":95},[33,879,110],{"class":65},[33,881,113],{"class":73},[33,883,884,886,888,890,892,894,897,899,902,905,907,909,912,914,916],{"class":35,"line":101},[33,885,119],{"class":73},[33,887,282],{"class":122},[33,889,126],{"class":69},[33,891,129],{"class":65},[33,893,161],{"class":73},[33,895,896],{"class":132},"`btn btn--${",[33,898,853],{"class":73},[33,900,901],{"class":132},"}`",[33,903,904],{"class":73},"} ",[33,906,863],{"class":69},[33,908,129],{"class":65},[33,910,911],{"class":73},"{disabled} ",[33,913,873],{"class":69},[33,915,129],{"class":65},[33,917,918],{"class":73},"{onClick}>\n",[33,920,921],{"class":35,"line":107},[33,922,773],{"class":73},[33,924,925,927,929],{"class":35,"line":116},[33,926,208],{"class":73},[33,928,282],{"class":122},[33,930,136],{"class":73},[33,932,933],{"class":35,"line":139},[33,934,218],{"class":73},[33,936,937],{"class":35,"line":175},[33,938,224],{"class":73},[33,940,941],{"class":35,"line":190},[33,942,59],{"emptyLinePlaceholder":58},[33,944,945,948,951,954,956,959,962,964,967],{"class":35,"line":205},[33,946,947],{"class":73},"\u003C",[33,949,950],{"class":438},"Button",[33,952,953],{"class":69}," label",[33,955,129],{"class":65},[33,957,958],{"class":132},"\"Save\"",[33,960,961],{"class":69}," onClick",[33,963,129],{"class":65},[33,965,966],{"class":73},"{handleSave} \u002F>              ",[33,968,969],{"class":39},"\u002F\u002F variant='primary'\n",[33,971,972,974,976,978,980,983,986,988,991,993,995,998],{"class":35,"line":215},[33,973,947],{"class":73},[33,975,950],{"class":438},[33,977,953],{"class":69},[33,979,129],{"class":65},[33,981,982],{"class":132},"\"Delete\"",[33,984,985],{"class":69}," variant",[33,987,129],{"class":65},[33,989,990],{"class":132},"\"danger\"",[33,992,961],{"class":69},[33,994,129],{"class":65},[33,996,997],{"class":73},"{fn} \u002F>   ",[33,999,1000],{"class":39},"\u002F\u002F variant='danger'\n",[180,1002,1004,1005,1008,1009],{"id":1003},"gotcha-defaults-apply-only-to-undefined-never-to-null","Gotcha: Defaults Apply Only to ",[30,1006,1007],{},"undefined",", Never to ",[30,1010,1011],{},"null",[19,1013,1015],{"filename":1014,"language":22},"default_vs_null.js",[24,1016,1018],{"className":26,"code":1017,"language":22,"meta":28,"style":28},"\u002F\u002F Default parameters trigger when the value is `undefined` (omitted OR explicit undefined).\n\u002F\u002F Passing `null` is a REAL value — the default is skipped entirely.\n\u002F\u002F This bites when an API returns `null` for \"empty\" and you expected the default.\n\nfunction Avatar({ size = 40 }) {\n  return \u003Cdiv style={{ width: size, height: size }} \u002F>\n}\n\n\u003CAvatar \u002F>                    \u002F\u002F size = 40  (undefined → default applies)\n\u003CAvatar size={undefined} \u002F>   \u002F\u002F size = 40  (explicit undefined → default applies)\n\u003CAvatar size={null} \u002F>        \u002F\u002F size = null (null is a real value → NO default)\n\u002F\u002F → style={{ width: null, height: null }} → renders with no width\u002Fheight, silently\n\n\u002F\u002F FIX if null should fall back to default: coalesce explicitly in the body.\nfunction AvatarSafe({ size }) {\n  const resolved = size ?? 40  \u002F\u002F null OR undefined → 40\n  return \u003Cdiv style={{ width: resolved, height: resolved }} \u002F>\n}\n",[30,1019,1020,1025,1030,1035,1039,1058,1074,1078,1082,1095,1116,1136,1141,1145,1150,1163,1184,1199],{"__ignoreMap":28},[33,1021,1022],{"class":35,"line":36},[33,1023,1024],{"class":39},"\u002F\u002F Default parameters trigger when the value is `undefined` (omitted OR explicit undefined).\n",[33,1026,1027],{"class":35,"line":43},[33,1028,1029],{"class":39},"\u002F\u002F Passing `null` is a REAL value — the default is skipped entirely.\n",[33,1031,1032],{"class":35,"line":49},[33,1033,1034],{"class":39},"\u002F\u002F This bites when an API returns `null` for \"empty\" and you expected the default.\n",[33,1036,1037],{"class":35,"line":55},[33,1038,59],{"emptyLinePlaceholder":58},[33,1040,1041,1043,1046,1048,1051,1053,1056],{"class":35,"line":62},[33,1042,66],{"class":65},[33,1044,1045],{"class":69}," Avatar",[33,1047,74],{"class":73},[33,1049,1050],{"class":77},"size",[33,1052,309],{"class":65},[33,1054,1055],{"class":438}," 40",[33,1057,92],{"class":73},[33,1059,1060,1062,1064,1066,1069,1071],{"class":35,"line":95},[33,1061,110],{"class":65},[33,1063,279],{"class":73},[33,1065,123],{"class":122},[33,1067,1068],{"class":69}," style",[33,1070,129],{"class":65},[33,1072,1073],{"class":73},"{{ width: size, height: size }} \u002F>\n",[33,1075,1076],{"class":35,"line":101},[33,1077,224],{"class":73},[33,1079,1080],{"class":35,"line":107},[33,1081,59],{"emptyLinePlaceholder":58},[33,1083,1084,1086,1089,1092],{"class":35,"line":116},[33,1085,947],{"class":73},[33,1087,1088],{"class":438},"Avatar",[33,1090,1091],{"class":73}," \u002F>                    ",[33,1093,1094],{"class":39},"\u002F\u002F size = 40  (undefined → default applies)\n",[33,1096,1097,1099,1101,1104,1106,1108,1110,1113],{"class":35,"line":139},[33,1098,947],{"class":73},[33,1100,1088],{"class":438},[33,1102,1103],{"class":69}," size",[33,1105,129],{"class":65},[33,1107,161],{"class":73},[33,1109,1007],{"class":438},[33,1111,1112],{"class":73},"} \u002F>   ",[33,1114,1115],{"class":39},"\u002F\u002F size = 40  (explicit undefined → default applies)\n",[33,1117,1118,1120,1122,1124,1126,1128,1130,1133],{"class":35,"line":175},[33,1119,947],{"class":73},[33,1121,1088],{"class":438},[33,1123,1103],{"class":69},[33,1125,129],{"class":65},[33,1127,161],{"class":73},[33,1129,1011],{"class":438},[33,1131,1132],{"class":73},"} \u002F>        ",[33,1134,1135],{"class":39},"\u002F\u002F size = null (null is a real value → NO default)\n",[33,1137,1138],{"class":35,"line":190},[33,1139,1140],{"class":39},"\u002F\u002F → style={{ width: null, height: null }} → renders with no width\u002Fheight, silently\n",[33,1142,1143],{"class":35,"line":205},[33,1144,59],{"emptyLinePlaceholder":58},[33,1146,1147],{"class":35,"line":215},[33,1148,1149],{"class":39},"\u002F\u002F FIX if null should fall back to default: coalesce explicitly in the body.\n",[33,1151,1152,1154,1157,1159,1161],{"class":35,"line":221},[33,1153,66],{"class":65},[33,1155,1156],{"class":69}," AvatarSafe",[33,1158,74],{"class":73},[33,1160,1050],{"class":77},[33,1162,92],{"class":73},[33,1164,1165,1168,1171,1173,1176,1179,1181],{"class":35,"line":227},[33,1166,1167],{"class":65},"  const",[33,1169,1170],{"class":438}," resolved",[33,1172,309],{"class":65},[33,1174,1175],{"class":73}," size ",[33,1177,1178],{"class":65},"??",[33,1180,1055],{"class":438},[33,1182,1183],{"class":39},"  \u002F\u002F null OR undefined → 40\n",[33,1185,1186,1188,1190,1192,1194,1196],{"class":35,"line":232},[33,1187,110],{"class":65},[33,1189,279],{"class":73},[33,1191,123],{"class":122},[33,1193,1068],{"class":69},[33,1195,129],{"class":65},[33,1197,1198],{"class":73},"{{ width: resolved, height: resolved }} \u002F>\n",[33,1200,1201],{"class":35,"line":496},[33,1202,224],{"class":73},[14,1204,1206],{"id":1205},"props-are-read-only-the-referential-equality-contract","Props Are Read-Only — The Referential Equality Contract",[19,1208,1210],{"filename":1209,"language":22},"props_readonly_contract.js",[24,1211,1213],{"className":26,"code":1212,"language":22,"meta":28,"style":28},"\u002F\u002F React's reconciliation compares previous props to next props by REFERENCE.\n\u002F\u002F If the object identity is unchanged, React may skip re-rendering the subtree.\n\u002F\u002F Mutating a prop object in place leaves the reference unchanged → React thinks\n\u002F\u002F nothing changed → no re-render → your UI is stale AND the parent's data is\n\u002F\u002F corrupted because objects are passed by reference, not copied.\n\n\u002F\u002F BROKEN: mutates the parent's object, React never knows, siblings see corruption.\nfunction BadName({ user }) {\n  user.name = user.name.toUpperCase()  \u002F\u002F ← mutates parent's `user` object\n  return \u003Cp>{user.name}\u003C\u002Fp>\n}\n\n\u002F\u002F CORRECT: derive a new value in render; never touch the input object.\nfunction GoodName({ user }) {\n  return \u003Cp>{user.name.toUpperCase()}\u003C\u002Fp>\n}\n",[30,1214,1215,1220,1225,1230,1235,1240,1244,1249,1263,1282,1297,1301,1305,1310,1323,1343],{"__ignoreMap":28},[33,1216,1217],{"class":35,"line":36},[33,1218,1219],{"class":39},"\u002F\u002F React's reconciliation compares previous props to next props by REFERENCE.\n",[33,1221,1222],{"class":35,"line":43},[33,1223,1224],{"class":39},"\u002F\u002F If the object identity is unchanged, React may skip re-rendering the subtree.\n",[33,1226,1227],{"class":35,"line":49},[33,1228,1229],{"class":39},"\u002F\u002F Mutating a prop object in place leaves the reference unchanged → React thinks\n",[33,1231,1232],{"class":35,"line":55},[33,1233,1234],{"class":39},"\u002F\u002F nothing changed → no re-render → your UI is stale AND the parent's data is\n",[33,1236,1237],{"class":35,"line":62},[33,1238,1239],{"class":39},"\u002F\u002F corrupted because objects are passed by reference, not copied.\n",[33,1241,1242],{"class":35,"line":95},[33,1243,59],{"emptyLinePlaceholder":58},[33,1245,1246],{"class":35,"line":101},[33,1247,1248],{"class":39},"\u002F\u002F BROKEN: mutates the parent's object, React never knows, siblings see corruption.\n",[33,1250,1251,1253,1256,1258,1261],{"class":35,"line":107},[33,1252,66],{"class":65},[33,1254,1255],{"class":69}," BadName",[33,1257,74],{"class":73},[33,1259,1260],{"class":77},"user",[33,1262,92],{"class":73},[33,1264,1265,1268,1270,1273,1276,1279],{"class":35,"line":116},[33,1266,1267],{"class":73},"  user.name ",[33,1269,129],{"class":65},[33,1271,1272],{"class":73}," user.name.",[33,1274,1275],{"class":69},"toUpperCase",[33,1277,1278],{"class":73},"()  ",[33,1280,1281],{"class":39},"\u002F\u002F ← mutates parent's `user` object\n",[33,1283,1284,1286,1288,1290,1293,1295],{"class":35,"line":139},[33,1285,110],{"class":65},[33,1287,279],{"class":73},[33,1289,195],{"class":122},[33,1291,1292],{"class":73},">{user.name}\u003C\u002F",[33,1294,195],{"class":122},[33,1296,136],{"class":73},[33,1298,1299],{"class":35,"line":175},[33,1300,224],{"class":73},[33,1302,1303],{"class":35,"line":190},[33,1304,59],{"emptyLinePlaceholder":58},[33,1306,1307],{"class":35,"line":205},[33,1308,1309],{"class":39},"\u002F\u002F CORRECT: derive a new value in render; never touch the input object.\n",[33,1311,1312,1314,1317,1319,1321],{"class":35,"line":215},[33,1313,66],{"class":65},[33,1315,1316],{"class":69}," GoodName",[33,1318,74],{"class":73},[33,1320,1260],{"class":77},[33,1322,92],{"class":73},[33,1324,1325,1327,1329,1331,1334,1336,1339,1341],{"class":35,"line":221},[33,1326,110],{"class":65},[33,1328,279],{"class":73},[33,1330,195],{"class":122},[33,1332,1333],{"class":73},">{user.name.",[33,1335,1275],{"class":69},[33,1337,1338],{"class":73},"()}\u003C\u002F",[33,1340,195],{"class":122},[33,1342,136],{"class":73},[33,1344,1345],{"class":35,"line":227},[33,1346,224],{"class":73},[180,1348,1350],{"id":1349},"why-mutation-breaks-reconciliation","Why Mutation Breaks Reconciliation",[19,1352,1354],{"filename":1353,"language":22},"reconciliation_equality.js",[24,1355,1357],{"className":26,"code":1356,"language":22,"meta":28,"style":28},"\u002F\u002F React's bailout optimization (simplified):\n\u002F\u002F   if (prevProps === nextProps || shallowEqual(prevProps, nextProps)) skip render\n\u002F\u002F\n\u002F\u002F shallowEqual checks each prop key with Object.is — a referential comparison.\n\u002F\u002F Mutating the contents of an object prop doesn't change its identity, so\n\u002F\u002F Object.is(prevProps.user, nextProps.user) → true even though contents differ.\n\u002F\u002F\n\u002F\u002F Result: React skips the re-render, the child shows stale data, AND the parent\n\u002F\u002F now holds a mutated object it didn't expect — two bugs for the price of one.\n\n\u002F\u002F SAFE PATTERN: if the child needs to \"change\" a prop, call a callback so the\n\u002F\u002F OWNER of the state produces a new immutable object and re-renders correctly.\nfunction EditableName({ user, onUpdate }) {\n  return (\n    \u003Cinput\n      value={user.name}\n      onChange={(e) => onUpdate({ ...user, name: e.target.value })}  \u002F\u002F new object\n    \u002F>\n  )\n}\n",[30,1358,1359,1364,1369,1374,1379,1384,1389,1393,1398,1403,1407,1412,1417,1435,1441,1448,1458,1489,1494,1498],{"__ignoreMap":28},[33,1360,1361],{"class":35,"line":36},[33,1362,1363],{"class":39},"\u002F\u002F React's bailout optimization (simplified):\n",[33,1365,1366],{"class":35,"line":43},[33,1367,1368],{"class":39},"\u002F\u002F   if (prevProps === nextProps || shallowEqual(prevProps, nextProps)) skip render\n",[33,1370,1371],{"class":35,"line":49},[33,1372,1373],{"class":39},"\u002F\u002F\n",[33,1375,1376],{"class":35,"line":55},[33,1377,1378],{"class":39},"\u002F\u002F shallowEqual checks each prop key with Object.is — a referential comparison.\n",[33,1380,1381],{"class":35,"line":62},[33,1382,1383],{"class":39},"\u002F\u002F Mutating the contents of an object prop doesn't change its identity, so\n",[33,1385,1386],{"class":35,"line":95},[33,1387,1388],{"class":39},"\u002F\u002F Object.is(prevProps.user, nextProps.user) → true even though contents differ.\n",[33,1390,1391],{"class":35,"line":101},[33,1392,1373],{"class":39},[33,1394,1395],{"class":35,"line":107},[33,1396,1397],{"class":39},"\u002F\u002F Result: React skips the re-render, the child shows stale data, AND the parent\n",[33,1399,1400],{"class":35,"line":116},[33,1401,1402],{"class":39},"\u002F\u002F now holds a mutated object it didn't expect — two bugs for the price of one.\n",[33,1404,1405],{"class":35,"line":139},[33,1406,59],{"emptyLinePlaceholder":58},[33,1408,1409],{"class":35,"line":175},[33,1410,1411],{"class":39},"\u002F\u002F SAFE PATTERN: if the child needs to \"change\" a prop, call a callback so the\n",[33,1413,1414],{"class":35,"line":190},[33,1415,1416],{"class":39},"\u002F\u002F OWNER of the state produces a new immutable object and re-renders correctly.\n",[33,1418,1419,1421,1424,1426,1428,1430,1433],{"class":35,"line":205},[33,1420,66],{"class":65},[33,1422,1423],{"class":69}," EditableName",[33,1425,74],{"class":73},[33,1427,1260],{"class":77},[33,1429,81],{"class":73},[33,1431,1432],{"class":77},"onUpdate",[33,1434,92],{"class":73},[33,1436,1437,1439],{"class":35,"line":215},[33,1438,110],{"class":65},[33,1440,113],{"class":73},[33,1442,1443,1445],{"class":35,"line":221},[33,1444,119],{"class":73},[33,1446,1447],{"class":122},"input\n",[33,1449,1450,1453,1455],{"class":35,"line":227},[33,1451,1452],{"class":69},"      value",[33,1454,129],{"class":65},[33,1456,1457],{"class":73},"{user.name}\n",[33,1459,1460,1463,1465,1468,1471,1474,1476,1479,1481,1483,1486],{"class":35,"line":232},[33,1461,1462],{"class":69},"      onChange",[33,1464,129],{"class":65},[33,1466,1467],{"class":73},"{(",[33,1469,1470],{"class":77},"e",[33,1472,1473],{"class":73},") ",[33,1475,320],{"class":65},[33,1477,1478],{"class":69}," onUpdate",[33,1480,74],{"class":73},[33,1482,749],{"class":65},[33,1484,1485],{"class":73},"user, name: e.target.value })}  ",[33,1487,1488],{"class":39},"\u002F\u002F new object\n",[33,1490,1491],{"class":35,"line":496},[33,1492,1493],{"class":73},"    \u002F>\n",[33,1495,1496],{"class":35,"line":503},[33,1497,218],{"class":73},[33,1499,1500],{"class":35,"line":509},[33,1501,224],{"class":73},[14,1503,1505],{"id":1504},"prop-types-and-validation","Prop Types and Validation",[180,1507,1509],{"id":1508},"proptypes-runtime-validation-legacy-literacy","PropTypes — Runtime Validation (Legacy-Literacy)",[19,1511,1513],{"filename":1512,"language":22},"proptypes.js",[24,1514,1516],{"className":26,"code":1515,"language":22,"meta":28,"style":28},"import PropTypes from 'prop-types'\n\n\u002F\u002F PropTypes runs ONLY in development, logs console warnings on mismatch.\n\u002F\u002F Zero compile-time safety, zero editor autocomplete. Seen in legacy codebases.\n\u002F\u002F For any new project, use TypeScript instead (next section).\n\nfunction UserCard({ name, age, friends, onUpdate }) {\n  return \u003Cp>{name} is {age} with {friends.length} friends\u003C\u002Fp>\n}\n\nUserCard.propTypes = {\n  name: PropTypes.string.isRequired,\n  age: PropTypes.number,\n  friends: PropTypes.arrayOf(\n    PropTypes.shape({\n      id: PropTypes.number.isRequired,\n      name: PropTypes.string,\n    })\n  ),\n  onUpdate: PropTypes.func,\n}\n",[30,1517,1518,1532,1536,1541,1546,1551,1555,1581,1602,1606,1610,1620,1625,1630,1641,1652,1657,1662,1667,1672,1677],{"__ignoreMap":28},[33,1519,1520,1523,1526,1529],{"class":35,"line":36},[33,1521,1522],{"class":65},"import",[33,1524,1525],{"class":73}," PropTypes ",[33,1527,1528],{"class":65},"from",[33,1530,1531],{"class":132}," 'prop-types'\n",[33,1533,1534],{"class":35,"line":43},[33,1535,59],{"emptyLinePlaceholder":58},[33,1537,1538],{"class":35,"line":49},[33,1539,1540],{"class":39},"\u002F\u002F PropTypes runs ONLY in development, logs console warnings on mismatch.\n",[33,1542,1543],{"class":35,"line":55},[33,1544,1545],{"class":39},"\u002F\u002F Zero compile-time safety, zero editor autocomplete. Seen in legacy codebases.\n",[33,1547,1548],{"class":35,"line":62},[33,1549,1550],{"class":39},"\u002F\u002F For any new project, use TypeScript instead (next section).\n",[33,1552,1553],{"class":35,"line":95},[33,1554,59],{"emptyLinePlaceholder":58},[33,1556,1557,1559,1561,1563,1565,1567,1570,1572,1575,1577,1579],{"class":35,"line":101},[33,1558,66],{"class":65},[33,1560,70],{"class":69},[33,1562,74],{"class":73},[33,1564,78],{"class":77},[33,1566,81],{"class":73},[33,1568,1569],{"class":77},"age",[33,1571,81],{"class":73},[33,1573,1574],{"class":77},"friends",[33,1576,81],{"class":73},[33,1578,1432],{"class":77},[33,1580,92],{"class":73},[33,1582,1583,1585,1587,1589,1592,1595,1598,1600],{"class":35,"line":107},[33,1584,110],{"class":65},[33,1586,279],{"class":73},[33,1588,195],{"class":122},[33,1590,1591],{"class":73},">{name} is {age} with {friends.",[33,1593,1594],{"class":438},"length",[33,1596,1597],{"class":73},"} friends\u003C\u002F",[33,1599,195],{"class":122},[33,1601,136],{"class":73},[33,1603,1604],{"class":35,"line":116},[33,1605,224],{"class":73},[33,1607,1608],{"class":35,"line":139},[33,1609,59],{"emptyLinePlaceholder":58},[33,1611,1612,1615,1617],{"class":35,"line":175},[33,1613,1614],{"class":73},"UserCard.propTypes ",[33,1616,129],{"class":65},[33,1618,1619],{"class":73}," {\n",[33,1621,1622],{"class":35,"line":190},[33,1623,1624],{"class":73},"  name: PropTypes.string.isRequired,\n",[33,1626,1627],{"class":35,"line":205},[33,1628,1629],{"class":73},"  age: PropTypes.number,\n",[33,1631,1632,1635,1638],{"class":35,"line":215},[33,1633,1634],{"class":73},"  friends: PropTypes.",[33,1636,1637],{"class":69},"arrayOf",[33,1639,1640],{"class":73},"(\n",[33,1642,1643,1646,1649],{"class":35,"line":221},[33,1644,1645],{"class":73},"    PropTypes.",[33,1647,1648],{"class":69},"shape",[33,1650,1651],{"class":73},"({\n",[33,1653,1654],{"class":35,"line":227},[33,1655,1656],{"class":73},"      id: PropTypes.number.isRequired,\n",[33,1658,1659],{"class":35,"line":232},[33,1660,1661],{"class":73},"      name: PropTypes.string,\n",[33,1663,1664],{"class":35,"line":496},[33,1665,1666],{"class":73},"    })\n",[33,1668,1669],{"class":35,"line":503},[33,1670,1671],{"class":73},"  ),\n",[33,1673,1674],{"class":35,"line":509},[33,1675,1676],{"class":73},"  onUpdate: PropTypes.func,\n",[33,1678,1679],{"class":35,"line":523},[33,1680,224],{"class":73},[180,1682,1684],{"id":1683},"typescript-interfaces-compile-time-safety-modern-default","TypeScript Interfaces — Compile-Time Safety (Modern Default)",[19,1686,1689],{"filename":1687,"language":1688},"typescript_props.ts","typescript",[24,1690,1693],{"className":1691,"code":1692,"language":1688,"meta":28,"style":28},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F Interfaces give you compile-time errors BEFORE the code runs, editor\n\u002F\u002F autocomplete on every prop, and refactor-safe renaming. This is the default\n\u002F\u002F for any project past a prototype.\n\ninterface UserCardProps {\n  name: string          \u002F\u002F required — no `?`\n  age?: number          \u002F\u002F optional — `?` means `| undefined`\n  friends?: Friend[]    \u002F\u002F array of typed objects\n  onUpdate?: (next: User) => void\n}\n\ninterface Friend {\n  id: number\n  name: string\n}\n\ninterface User {\n  name: string\n  age?: number\n}\n\nfunction UserCard({ name, age, friends = [], onUpdate }: UserCardProps) {\n  return \u003Cp>{name} is {age} with {friends.length} friends\u003C\u002Fp>\n}\n\n\u002F\u002F WRONG: \u003CUserCard name={123} \u002F>         \u002F\u002F TS error: number not assignable to string\n\u002F\u002F WRONG: \u003CUserCard name=\"A\" age=\"old\" \u002F> \u002F\u002F TS error: string not assignable to number\n\u002F\u002F RIGHT: \u003CUserCard name=\"Alice\" age={30} \u002F>\n",[30,1694,1695,1700,1705,1710,1714,1724,1738,1752,1768,1792,1796,1800,1808,1818,1827,1831,1835,1843,1851,1859,1863,1867,1901,1919,1923,1928,1937,1946],{"__ignoreMap":28},[33,1696,1697],{"class":35,"line":36},[33,1698,1699],{"class":39},"\u002F\u002F Interfaces give you compile-time errors BEFORE the code runs, editor\n",[33,1701,1702],{"class":35,"line":43},[33,1703,1704],{"class":39},"\u002F\u002F autocomplete on every prop, and refactor-safe renaming. This is the default\n",[33,1706,1707],{"class":35,"line":49},[33,1708,1709],{"class":39},"\u002F\u002F for any project past a prototype.\n",[33,1711,1712],{"class":35,"line":55},[33,1713,59],{"emptyLinePlaceholder":58},[33,1715,1716,1719,1722],{"class":35,"line":62},[33,1717,1718],{"class":65},"interface",[33,1720,1721],{"class":69}," UserCardProps",[33,1723,1619],{"class":73},[33,1725,1726,1729,1732,1735],{"class":35,"line":95},[33,1727,1728],{"class":77},"  name",[33,1730,1731],{"class":65},":",[33,1733,1734],{"class":438}," string",[33,1736,1737],{"class":39},"          \u002F\u002F required — no `?`\n",[33,1739,1740,1743,1746,1749],{"class":35,"line":101},[33,1741,1742],{"class":77},"  age",[33,1744,1745],{"class":65},"?:",[33,1747,1748],{"class":438}," number",[33,1750,1751],{"class":39},"          \u002F\u002F optional — `?` means `| undefined`\n",[33,1753,1754,1757,1759,1762,1765],{"class":35,"line":107},[33,1755,1756],{"class":77},"  friends",[33,1758,1745],{"class":65},[33,1760,1761],{"class":69}," Friend",[33,1763,1764],{"class":73},"[]    ",[33,1766,1767],{"class":39},"\u002F\u002F array of typed objects\n",[33,1769,1770,1773,1775,1777,1780,1782,1785,1787,1789],{"class":35,"line":116},[33,1771,1772],{"class":69},"  onUpdate",[33,1774,1745],{"class":65},[33,1776,427],{"class":73},[33,1778,1779],{"class":77},"next",[33,1781,1731],{"class":65},[33,1783,1784],{"class":69}," User",[33,1786,1473],{"class":73},[33,1788,320],{"class":65},[33,1790,1791],{"class":438}," void\n",[33,1793,1794],{"class":35,"line":139},[33,1795,224],{"class":73},[33,1797,1798],{"class":35,"line":175},[33,1799,59],{"emptyLinePlaceholder":58},[33,1801,1802,1804,1806],{"class":35,"line":190},[33,1803,1718],{"class":65},[33,1805,1761],{"class":69},[33,1807,1619],{"class":73},[33,1809,1810,1813,1815],{"class":35,"line":205},[33,1811,1812],{"class":77},"  id",[33,1814,1731],{"class":65},[33,1816,1817],{"class":438}," number\n",[33,1819,1820,1822,1824],{"class":35,"line":215},[33,1821,1728],{"class":77},[33,1823,1731],{"class":65},[33,1825,1826],{"class":438}," string\n",[33,1828,1829],{"class":35,"line":221},[33,1830,224],{"class":73},[33,1832,1833],{"class":35,"line":227},[33,1834,59],{"emptyLinePlaceholder":58},[33,1836,1837,1839,1841],{"class":35,"line":232},[33,1838,1718],{"class":65},[33,1840,1784],{"class":69},[33,1842,1619],{"class":73},[33,1844,1845,1847,1849],{"class":35,"line":496},[33,1846,1728],{"class":77},[33,1848,1731],{"class":65},[33,1850,1826],{"class":438},[33,1852,1853,1855,1857],{"class":35,"line":503},[33,1854,1742],{"class":77},[33,1856,1745],{"class":65},[33,1858,1817],{"class":438},[33,1860,1861],{"class":35,"line":509},[33,1862,224],{"class":73},[33,1864,1865],{"class":35,"line":523},[33,1866,59],{"emptyLinePlaceholder":58},[33,1868,1869,1871,1873,1875,1877,1879,1881,1883,1885,1887,1890,1892,1895,1897,1899],{"class":35,"line":537},[33,1870,66],{"class":65},[33,1872,70],{"class":69},[33,1874,74],{"class":73},[33,1876,78],{"class":77},[33,1878,81],{"class":73},[33,1880,1569],{"class":77},[33,1882,81],{"class":73},[33,1884,1574],{"class":77},[33,1886,309],{"class":65},[33,1888,1889],{"class":73}," [], ",[33,1891,1432],{"class":77},[33,1893,1894],{"class":73}," }",[33,1896,1731],{"class":65},[33,1898,1721],{"class":69},[33,1900,583],{"class":73},[33,1902,1903,1905,1907,1909,1912,1915,1917],{"class":35,"line":543},[33,1904,110],{"class":65},[33,1906,279],{"class":73},[33,1908,195],{"class":69},[33,1910,1911],{"class":73},">{name} is {age} with {friends.length} friends",[33,1913,1914],{"class":65},"\u003C\u002F",[33,1916,195],{"class":73},[33,1918,136],{"class":65},[33,1920,1921],{"class":35,"line":548},[33,1922,224],{"class":73},[33,1924,1926],{"class":35,"line":1925},25,[33,1927,59],{"emptyLinePlaceholder":58},[33,1929,1931,1934],{"class":35,"line":1930},26,[33,1932,1933],{"class":39},"\u002F\u002F WRONG: \u003CUserCard name={123} \u002F>",[33,1935,1936],{"class":39},"         \u002F\u002F TS error: number not assignable to string\n",[33,1938,1940,1943],{"class":35,"line":1939},27,[33,1941,1942],{"class":39},"\u002F\u002F WRONG: \u003CUserCard name=\"A\" age=\"old\" \u002F>",[33,1944,1945],{"class":39}," \u002F\u002F TS error: string not assignable to number\n",[33,1947,1949],{"class":35,"line":1948},28,[33,1950,1951],{"class":39},"\u002F\u002F RIGHT: \u003CUserCard name=\"Alice\" age={30} \u002F>\n",[180,1953,1955,1958,1959,1961],{"id":1954},"type-alias-vs-interface-for-props",[30,1956,1957],{},"type"," Alias vs ",[30,1960,1718],{}," for Props",[19,1963,1965],{"filename":1964,"language":1688},"type_vs_interface.ts",[24,1966,1968],{"className":1691,"code":1967,"language":1688,"meta":28,"style":28},"\u002F\u002F Both work identically for props. The practical differences:\n\n\u002F\u002F interface — extendable via declaration merging; open for future augmentation.\ninterface ButtonProps { variant?: 'primary' | 'danger' }\n\u002F\u002F A library or your own file can later add:\n\u002F\u002F declare module '.\u002FButton' { interface ButtonProps { size?: 'sm' | 'lg' } }\n\n\u002F\u002F type alias — supports unions and computed\u002Fmapped types; cannot be merged.\ntype ButtonProps = { variant?: 'primary' | 'danger' } & { size?: 'sm' | 'lg' }\n\n\u002F\u002F RULE OF THUMB: use `interface` for simple object props (lets consumers augment),\n\u002F\u002F use `type` when you need unions, intersections, or mapped utility types.\n",[30,1969,1970,1975,1979,1984,2009,2014,2019,2023,2028,2070,2074,2079],{"__ignoreMap":28},[33,1971,1972],{"class":35,"line":36},[33,1973,1974],{"class":39},"\u002F\u002F Both work identically for props. The practical differences:\n",[33,1976,1977],{"class":35,"line":43},[33,1978,59],{"emptyLinePlaceholder":58},[33,1980,1981],{"class":35,"line":49},[33,1982,1983],{"class":39},"\u002F\u002F interface — extendable via declaration merging; open for future augmentation.\n",[33,1985,1986,1988,1991,1994,1996,1998,2000,2003,2006],{"class":35,"line":55},[33,1987,1718],{"class":65},[33,1989,1990],{"class":69}," ButtonProps",[33,1992,1993],{"class":73}," { ",[33,1995,853],{"class":77},[33,1997,1745],{"class":65},[33,1999,858],{"class":132},[33,2001,2002],{"class":65}," |",[33,2004,2005],{"class":132}," 'danger'",[33,2007,2008],{"class":73}," }\n",[33,2010,2011],{"class":35,"line":62},[33,2012,2013],{"class":39},"\u002F\u002F A library or your own file can later add:\n",[33,2015,2016],{"class":35,"line":95},[33,2017,2018],{"class":39},"\u002F\u002F declare module '.\u002FButton' { interface ButtonProps { size?: 'sm' | 'lg' } }\n",[33,2020,2021],{"class":35,"line":101},[33,2022,59],{"emptyLinePlaceholder":58},[33,2024,2025],{"class":35,"line":107},[33,2026,2027],{"class":39},"\u002F\u002F type alias — supports unions and computed\u002Fmapped types; cannot be merged.\n",[33,2029,2030,2032,2034,2036,2038,2040,2042,2044,2046,2048,2051,2054,2056,2058,2060,2063,2065,2068],{"class":35,"line":116},[33,2031,1957],{"class":65},[33,2033,1990],{"class":69},[33,2035,309],{"class":65},[33,2037,1993],{"class":73},[33,2039,853],{"class":77},[33,2041,1745],{"class":65},[33,2043,858],{"class":132},[33,2045,2002],{"class":65},[33,2047,2005],{"class":132},[33,2049,2050],{"class":73}," } ",[33,2052,2053],{"class":65},"&",[33,2055,1993],{"class":73},[33,2057,1050],{"class":77},[33,2059,1745],{"class":65},[33,2061,2062],{"class":132}," 'sm'",[33,2064,2002],{"class":65},[33,2066,2067],{"class":132}," 'lg'",[33,2069,2008],{"class":73},[33,2071,2072],{"class":35,"line":139},[33,2073,59],{"emptyLinePlaceholder":58},[33,2075,2076],{"class":35,"line":175},[33,2077,2078],{"class":39},"\u002F\u002F RULE OF THUMB: use `interface` for simple object props (lets consumers augment),\n",[33,2080,2081],{"class":35,"line":190},[33,2082,2083],{"class":39},"\u002F\u002F use `type` when you need unions, intersections, or mapped utility types.\n",[14,2085,2087,2088,2091],{"id":2086},"the-children-prop","The ",[30,2089,2090],{},"children"," Prop",[19,2093,2095],{"filename":2094,"language":22},"children_prop.js",[24,2096,2098],{"className":26,"code":2097,"language":22,"meta":28,"style":28},"\u002F\u002F Anything between opening and closing tags arrives as `children` automatically.\n\u002F\u002F children can be: string, number, element, array of elements, or null.\n\u002F\u002F It is THE foundation of composition (fully explored in Ch 15).\n\nfunction Card({ title, children }) {\n  return (\n    \u003Cdiv className=\"card\">\n      \u003Ch3>{title}\u003C\u002Fh3>\n      \u003Cdiv className=\"card__body\">{children}\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  )\n}\n\n\u003CCard title=\"Settings\">\n  \u003Cp>Manage your profile.\u003C\u002Fp>\n  \u003Cbutton>Edit\u003C\u002Fbutton>\n\u003C\u002FCard>\n\u002F\u002F children = [\u003Cp>…\u003C\u002Fp>, \u003Cbutton>…\u003C\u002Fbutton>]  (array when >1 child)\n",[30,2099,2100,2105,2110,2115,2119,2136,2142,2157,2169,2189,2197,2201,2205,2209,2226,2240,2253,2261],{"__ignoreMap":28},[33,2101,2102],{"class":35,"line":36},[33,2103,2104],{"class":39},"\u002F\u002F Anything between opening and closing tags arrives as `children` automatically.\n",[33,2106,2107],{"class":35,"line":43},[33,2108,2109],{"class":39},"\u002F\u002F children can be: string, number, element, array of elements, or null.\n",[33,2111,2112],{"class":35,"line":49},[33,2113,2114],{"class":39},"\u002F\u002F It is THE foundation of composition (fully explored in Ch 15).\n",[33,2116,2117],{"class":35,"line":55},[33,2118,59],{"emptyLinePlaceholder":58},[33,2120,2121,2123,2126,2128,2130,2132,2134],{"class":35,"line":62},[33,2122,66],{"class":65},[33,2124,2125],{"class":69}," Card",[33,2127,74],{"class":73},[33,2129,84],{"class":77},[33,2131,81],{"class":73},[33,2133,2090],{"class":77},[33,2135,92],{"class":73},[33,2137,2138,2140],{"class":35,"line":95},[33,2139,110],{"class":65},[33,2141,113],{"class":73},[33,2143,2144,2146,2148,2150,2152,2155],{"class":35,"line":101},[33,2145,119],{"class":73},[33,2147,123],{"class":122},[33,2149,126],{"class":69},[33,2151,129],{"class":65},[33,2153,2154],{"class":132},"\"card\"",[33,2156,136],{"class":73},[33,2158,2159,2161,2163,2165,2167],{"class":35,"line":107},[33,2160,142],{"class":73},[33,2162,180],{"class":122},[33,2164,198],{"class":73},[33,2166,180],{"class":122},[33,2168,136],{"class":73},[33,2170,2171,2173,2175,2177,2179,2182,2185,2187],{"class":35,"line":116},[33,2172,142],{"class":73},[33,2174,123],{"class":122},[33,2176,126],{"class":69},[33,2178,129],{"class":65},[33,2180,2181],{"class":132},"\"card__body\"",[33,2183,2184],{"class":73},">{children}\u003C\u002F",[33,2186,123],{"class":122},[33,2188,136],{"class":73},[33,2190,2191,2193,2195],{"class":35,"line":139},[33,2192,208],{"class":73},[33,2194,123],{"class":122},[33,2196,136],{"class":73},[33,2198,2199],{"class":35,"line":175},[33,2200,218],{"class":73},[33,2202,2203],{"class":35,"line":190},[33,2204,224],{"class":73},[33,2206,2207],{"class":35,"line":205},[33,2208,59],{"emptyLinePlaceholder":58},[33,2210,2211,2213,2216,2219,2221,2224],{"class":35,"line":215},[33,2212,947],{"class":73},[33,2214,2215],{"class":438},"Card",[33,2217,2218],{"class":69}," title",[33,2220,129],{"class":65},[33,2222,2223],{"class":132},"\"Settings\"",[33,2225,136],{"class":73},[33,2227,2228,2231,2233,2236,2238],{"class":35,"line":221},[33,2229,2230],{"class":73},"  \u003C",[33,2232,195],{"class":122},[33,2234,2235],{"class":73},">Manage your profile.\u003C\u002F",[33,2237,195],{"class":122},[33,2239,136],{"class":73},[33,2241,2242,2244,2246,2249,2251],{"class":35,"line":227},[33,2243,2230],{"class":73},[33,2245,282],{"class":122},[33,2247,2248],{"class":73},">Edit\u003C\u002F",[33,2250,282],{"class":122},[33,2252,136],{"class":73},[33,2254,2255,2257,2259],{"class":35,"line":232},[33,2256,1914],{"class":73},[33,2258,2215],{"class":438},[33,2260,136],{"class":73},[33,2262,2263],{"class":35,"line":496},[33,2264,2265],{"class":39},"\u002F\u002F children = [\u003Cp>…\u003C\u002Fp>, \u003Cbutton>…\u003C\u002Fbutton>]  (array when >1 child)\n",[180,2267,2269,2271],{"id":2268},"children-is-not-always-an-array",[30,2270,2090],{}," Is Not Always an Array",[19,2273,2275],{"filename":2274,"language":22},"children_count_gotcha.js",[24,2276,2278],{"className":26,"code":2277,"language":22,"meta":28,"style":28},"\u002F\u002F A component with EXACTLY ONE child receives that child directly — not an array.\n\u002F\u002F Code that unconditionally calls children.map(...) throws on the single-child case.\n\nfunction Broken({ children }) {\n  return \u003Cdiv>{children.map(child => \u003Cspan key={child.key}>{child}\u003C\u002Fspan>)}\u003C\u002Fdiv>\n  \u002F\u002F TypeError: children.map is not a function  (when single child is a string\u002Felement)\n}\n\n\u002F\u002F FIX 1: React.Children.map — handles single, multiple, and null uniformly.\nfunction Safe({ children }) {\n  return \u003Cdiv>{React.Children.map(children, c => \u003Cspan>{c}\u003C\u002Fspan>)}\u003C\u002Fdiv>\n}\n\n\u002F\u002F FIX 2: React.Children.count — reliable count regardless of structure.\nfunction Badge({ children, count }) {\n  const childCount = React.Children.count(children)\n  return \u003Cdiv data-count={childCount}>{children}\u003C\u002Fdiv>\n}\n\n\u002F\u002F FIX 3: normalize to array yourself if you need an actual array.\nconst arr = React.Children.toArray(children)  \u002F\u002F flattens, assigns keys, handles null\n",[30,2279,2280,2285,2290,2294,2307,2350,2355,2359,2363,2368,2381,2417,2421,2425,2430,2446,2463,2483,2487,2491,2496],{"__ignoreMap":28},[33,2281,2282],{"class":35,"line":36},[33,2283,2284],{"class":39},"\u002F\u002F A component with EXACTLY ONE child receives that child directly — not an array.\n",[33,2286,2287],{"class":35,"line":43},[33,2288,2289],{"class":39},"\u002F\u002F Code that unconditionally calls children.map(...) throws on the single-child case.\n",[33,2291,2292],{"class":35,"line":49},[33,2293,59],{"emptyLinePlaceholder":58},[33,2295,2296,2298,2301,2303,2305],{"class":35,"line":55},[33,2297,66],{"class":65},[33,2299,2300],{"class":69}," Broken",[33,2302,74],{"class":73},[33,2304,2090],{"class":77},[33,2306,92],{"class":73},[33,2308,2309,2311,2313,2315,2318,2321,2323,2326,2329,2331,2333,2336,2338,2341,2343,2346,2348],{"class":35,"line":62},[33,2310,110],{"class":65},[33,2312,279],{"class":73},[33,2314,123],{"class":122},[33,2316,2317],{"class":73},">{children.",[33,2319,2320],{"class":69},"map",[33,2322,577],{"class":73},[33,2324,2325],{"class":77},"child",[33,2327,2328],{"class":65}," =>",[33,2330,279],{"class":73},[33,2332,33],{"class":122},[33,2334,2335],{"class":69}," key",[33,2337,129],{"class":65},[33,2339,2340],{"class":73},"{child.key}>{child}\u003C\u002F",[33,2342,33],{"class":122},[33,2344,2345],{"class":73},">)}\u003C\u002F",[33,2347,123],{"class":122},[33,2349,136],{"class":73},[33,2351,2352],{"class":35,"line":95},[33,2353,2354],{"class":39},"  \u002F\u002F TypeError: children.map is not a function  (when single child is a string\u002Felement)\n",[33,2356,2357],{"class":35,"line":101},[33,2358,224],{"class":73},[33,2360,2361],{"class":35,"line":107},[33,2362,59],{"emptyLinePlaceholder":58},[33,2364,2365],{"class":35,"line":116},[33,2366,2367],{"class":39},"\u002F\u002F FIX 1: React.Children.map — handles single, multiple, and null uniformly.\n",[33,2369,2370,2372,2375,2377,2379],{"class":35,"line":139},[33,2371,66],{"class":65},[33,2373,2374],{"class":69}," Safe",[33,2376,74],{"class":73},[33,2378,2090],{"class":77},[33,2380,92],{"class":73},[33,2382,2383,2385,2387,2389,2392,2394,2397,2400,2402,2404,2406,2409,2411,2413,2415],{"class":35,"line":175},[33,2384,110],{"class":65},[33,2386,279],{"class":73},[33,2388,123],{"class":122},[33,2390,2391],{"class":73},">{React.Children.",[33,2393,2320],{"class":69},[33,2395,2396],{"class":73},"(children, ",[33,2398,2399],{"class":77},"c",[33,2401,2328],{"class":65},[33,2403,279],{"class":73},[33,2405,33],{"class":122},[33,2407,2408],{"class":73},">{c}\u003C\u002F",[33,2410,33],{"class":122},[33,2412,2345],{"class":73},[33,2414,123],{"class":122},[33,2416,136],{"class":73},[33,2418,2419],{"class":35,"line":190},[33,2420,224],{"class":73},[33,2422,2423],{"class":35,"line":205},[33,2424,59],{"emptyLinePlaceholder":58},[33,2426,2427],{"class":35,"line":215},[33,2428,2429],{"class":39},"\u002F\u002F FIX 2: React.Children.count — reliable count regardless of structure.\n",[33,2431,2432,2434,2436,2438,2440,2442,2444],{"class":35,"line":221},[33,2433,66],{"class":65},[33,2435,683],{"class":69},[33,2437,74],{"class":73},[33,2439,2090],{"class":77},[33,2441,81],{"class":73},[33,2443,688],{"class":77},[33,2445,92],{"class":73},[33,2447,2448,2450,2453,2455,2458,2460],{"class":35,"line":227},[33,2449,1167],{"class":65},[33,2451,2452],{"class":438}," childCount",[33,2454,309],{"class":65},[33,2456,2457],{"class":73}," React.Children.",[33,2459,688],{"class":69},[33,2461,2462],{"class":73},"(children)\n",[33,2464,2465,2467,2469,2471,2474,2476,2479,2481],{"class":35,"line":232},[33,2466,110],{"class":65},[33,2468,279],{"class":73},[33,2470,123],{"class":122},[33,2472,2473],{"class":69}," data-count",[33,2475,129],{"class":65},[33,2477,2478],{"class":73},"{childCount}>{children}\u003C\u002F",[33,2480,123],{"class":122},[33,2482,136],{"class":73},[33,2484,2485],{"class":35,"line":496},[33,2486,224],{"class":73},[33,2488,2489],{"class":35,"line":503},[33,2490,59],{"emptyLinePlaceholder":58},[33,2492,2493],{"class":35,"line":509},[33,2494,2495],{"class":39},"\u002F\u002F FIX 3: normalize to array yourself if you need an actual array.\n",[33,2497,2498,2500,2503,2505,2507,2510,2513],{"class":35,"line":523},[33,2499,304],{"class":65},[33,2501,2502],{"class":438}," arr",[33,2504,309],{"class":65},[33,2506,2457],{"class":73},[33,2508,2509],{"class":69},"toArray",[33,2511,2512],{"class":73},"(children)  ",[33,2514,2515],{"class":39},"\u002F\u002F flattens, assigns keys, handles null\n",[14,2517,2519],{"id":2518},"children-patterns-beyond-static-jsx","Children Patterns — Beyond Static JSX",[180,2521,2523],{"id":2522},"render-props-pass-a-function-that-returns-jsx","Render Props — Pass a Function That Returns JSX",[19,2525,2527],{"filename":2526,"language":22},"render_prop.js",[24,2528,2530],{"className":26,"code":2529,"language":22,"meta":28,"style":28},"\u002F\u002F A render prop is a function the child calls to decide what to render.\n\u002F\u002F It inverts control: the parent owns the data, the child owns the mechanism.\n\u002F\u002F Useful for sharing stateful logic WITHOUT hooks (pre-hooks era pattern, still valid).\n\nfunction MouseTracker({ render }) {\n  const [pos, setPos] = useState({ x: 0, y: 0 })\n  return (\n    \u003Cdiv onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>\n      {render(pos)}  {\u002F* parent decides how to display the position *\u002F}\n    \u003C\u002Fdiv>\n  )\n}\n\n\u003CMouseTracker render={({ x, y }) => \u003Cp>Cursor: {x}, {y}\u003C\u002Fp>} \u002F>\n\u003CMouseTracker render={({ x, y }) => \u003CCircle x={x} y={y} \u002F>} \u002F>\n",[30,2531,2532,2537,2542,2547,2551,2565,2602,2608,2633,2648,2656,2660,2664,2668,2707],{"__ignoreMap":28},[33,2533,2534],{"class":35,"line":36},[33,2535,2536],{"class":39},"\u002F\u002F A render prop is a function the child calls to decide what to render.\n",[33,2538,2539],{"class":35,"line":43},[33,2540,2541],{"class":39},"\u002F\u002F It inverts control: the parent owns the data, the child owns the mechanism.\n",[33,2543,2544],{"class":35,"line":49},[33,2545,2546],{"class":39},"\u002F\u002F Useful for sharing stateful logic WITHOUT hooks (pre-hooks era pattern, still valid).\n",[33,2548,2549],{"class":35,"line":55},[33,2550,59],{"emptyLinePlaceholder":58},[33,2552,2553,2555,2558,2560,2563],{"class":35,"line":62},[33,2554,66],{"class":65},[33,2556,2557],{"class":69}," MouseTracker",[33,2559,74],{"class":73},[33,2561,2562],{"class":77},"render",[33,2564,92],{"class":73},[33,2566,2567,2569,2572,2575,2577,2580,2583,2585,2588,2591,2594,2597,2599],{"class":35,"line":95},[33,2568,1167],{"class":65},[33,2570,2571],{"class":73}," [",[33,2573,2574],{"class":438},"pos",[33,2576,81],{"class":73},[33,2578,2579],{"class":438},"setPos",[33,2581,2582],{"class":73},"] ",[33,2584,129],{"class":65},[33,2586,2587],{"class":69}," useState",[33,2589,2590],{"class":73},"({ x: ",[33,2592,2593],{"class":438},"0",[33,2595,2596],{"class":73},", y: ",[33,2598,2593],{"class":438},[33,2600,2601],{"class":73}," })\n",[33,2603,2604,2606],{"class":35,"line":101},[33,2605,110],{"class":65},[33,2607,113],{"class":73},[33,2609,2610,2612,2614,2617,2619,2621,2623,2625,2627,2630],{"class":35,"line":107},[33,2611,119],{"class":73},[33,2613,123],{"class":122},[33,2615,2616],{"class":69}," onMouseMove",[33,2618,129],{"class":65},[33,2620,1467],{"class":73},[33,2622,1470],{"class":77},[33,2624,1473],{"class":73},[33,2626,320],{"class":65},[33,2628,2629],{"class":69}," setPos",[33,2631,2632],{"class":73},"({ x: e.clientX, y: e.clientY })}>\n",[33,2634,2635,2638,2640,2643,2646],{"class":35,"line":116},[33,2636,2637],{"class":73},"      {",[33,2639,2562],{"class":69},[33,2641,2642],{"class":73},"(pos)}  {",[33,2644,2645],{"class":39},"\u002F* parent decides how to display the position *\u002F",[33,2647,224],{"class":73},[33,2649,2650,2652,2654],{"class":35,"line":139},[33,2651,208],{"class":73},[33,2653,123],{"class":122},[33,2655,136],{"class":73},[33,2657,2658],{"class":35,"line":175},[33,2659,218],{"class":73},[33,2661,2662],{"class":35,"line":190},[33,2663,224],{"class":73},[33,2665,2666],{"class":35,"line":205},[33,2667,59],{"emptyLinePlaceholder":58},[33,2669,2670,2672,2675,2678,2680,2683,2686,2688,2691,2693,2695,2697,2699,2702,2704],{"class":35,"line":215},[33,2671,947],{"class":73},[33,2673,2674],{"class":438},"MouseTracker",[33,2676,2677],{"class":69}," render",[33,2679,129],{"class":65},[33,2681,2682],{"class":73},"{({ ",[33,2684,2685],{"class":77},"x",[33,2687,81],{"class":73},[33,2689,2690],{"class":77},"y",[33,2692,317],{"class":73},[33,2694,320],{"class":65},[33,2696,279],{"class":73},[33,2698,195],{"class":122},[33,2700,2701],{"class":73},">Cursor: {x}, {y}\u003C\u002F",[33,2703,195],{"class":122},[33,2705,2706],{"class":73},">} \u002F>\n",[33,2708,2709,2711,2713,2715,2717,2719,2721,2723,2725,2727,2729,2731,2734,2737,2739,2742,2744,2746],{"class":35,"line":221},[33,2710,947],{"class":73},[33,2712,2674],{"class":438},[33,2714,2677],{"class":69},[33,2716,129],{"class":65},[33,2718,2682],{"class":73},[33,2720,2685],{"class":77},[33,2722,81],{"class":73},[33,2724,2690],{"class":77},[33,2726,317],{"class":73},[33,2728,320],{"class":65},[33,2730,279],{"class":73},[33,2732,2733],{"class":438},"Circle",[33,2735,2736],{"class":69}," x",[33,2738,129],{"class":65},[33,2740,2741],{"class":73},"{x} ",[33,2743,2690],{"class":69},[33,2745,129],{"class":65},[33,2747,2748],{"class":73},"{y} \u002F>} \u002F>\n",[180,2750,2752,2753,2755],{"id":2751},"function-as-child-facc-children-itself-is-the-render-prop","Function-as-Child (FaCC) — ",[30,2754,2090],{}," Itself Is the Render Prop",[19,2757,2759],{"filename":2758,"language":22},"function_as_child.js",[24,2760,2762],{"className":26,"code":2761,"language":22,"meta":28,"style":28},"\u002F\u002F Instead of a named `render` prop, use `children` AS the function.\n\u002F\u002F This is the most idiomatic render-prop variant — the API reads as JSX nesting.\n\nfunction Toggle({ children }) {\n  const [on, setOn] = useState(false)\n  const toggle = () => setOn(v => !v)\n  return children({ on, toggle })  \u002F\u002F children is a FUNCTION, not JSX\n}\n\n\u002F\u002F Usage — looks like normal JSX nesting, but children is a callback.\n\u003CToggle>\n  {({ on, toggle }) => (\n    \u003Cbutton onClick={toggle}>{on ? 'On' : 'Off'}\u003C\u002Fbutton>\n  )}\n\u003C\u002FToggle>\n\n\u002F\u002F NOTE: In modern React, custom hooks (useToggle) are usually preferred over\n\u002F\u002F render props for reusable stateful logic. Render props remain valuable when\n\u002F\u002F the logic is tightly coupled to a DOM element the component renders.\n",[30,2763,2764,2769,2774,2778,2791,2819,2849,2862,2866,2870,2875,2884,2902,2934,2939,2947,2951,2956,2961],{"__ignoreMap":28},[33,2765,2766],{"class":35,"line":36},[33,2767,2768],{"class":39},"\u002F\u002F Instead of a named `render` prop, use `children` AS the function.\n",[33,2770,2771],{"class":35,"line":43},[33,2772,2773],{"class":39},"\u002F\u002F This is the most idiomatic render-prop variant — the API reads as JSX nesting.\n",[33,2775,2776],{"class":35,"line":49},[33,2777,59],{"emptyLinePlaceholder":58},[33,2779,2780,2782,2785,2787,2789],{"class":35,"line":55},[33,2781,66],{"class":65},[33,2783,2784],{"class":69}," Toggle",[33,2786,74],{"class":73},[33,2788,2090],{"class":77},[33,2790,92],{"class":73},[33,2792,2793,2795,2797,2800,2802,2805,2807,2809,2811,2813,2816],{"class":35,"line":62},[33,2794,1167],{"class":65},[33,2796,2571],{"class":73},[33,2798,2799],{"class":438},"on",[33,2801,81],{"class":73},[33,2803,2804],{"class":438},"setOn",[33,2806,2582],{"class":73},[33,2808,129],{"class":65},[33,2810,2587],{"class":69},[33,2812,577],{"class":73},[33,2814,2815],{"class":438},"false",[33,2817,2818],{"class":73},")\n",[33,2820,2821,2823,2826,2828,2831,2833,2836,2838,2841,2843,2846],{"class":35,"line":95},[33,2822,1167],{"class":65},[33,2824,2825],{"class":69}," toggle",[33,2827,309],{"class":65},[33,2829,2830],{"class":73}," () ",[33,2832,320],{"class":65},[33,2834,2835],{"class":69}," setOn",[33,2837,577],{"class":73},[33,2839,2840],{"class":77},"v",[33,2842,2328],{"class":65},[33,2844,2845],{"class":65}," !",[33,2847,2848],{"class":73},"v)\n",[33,2850,2851,2853,2856,2859],{"class":35,"line":101},[33,2852,110],{"class":65},[33,2854,2855],{"class":69}," children",[33,2857,2858],{"class":73},"({ on, toggle })  ",[33,2860,2861],{"class":39},"\u002F\u002F children is a FUNCTION, not JSX\n",[33,2863,2864],{"class":35,"line":107},[33,2865,224],{"class":73},[33,2867,2868],{"class":35,"line":116},[33,2869,59],{"emptyLinePlaceholder":58},[33,2871,2872],{"class":35,"line":139},[33,2873,2874],{"class":39},"\u002F\u002F Usage — looks like normal JSX nesting, but children is a callback.\n",[33,2876,2877,2879,2882],{"class":35,"line":175},[33,2878,947],{"class":73},[33,2880,2881],{"class":438},"Toggle",[33,2883,136],{"class":73},[33,2885,2886,2889,2891,2893,2896,2898,2900],{"class":35,"line":190},[33,2887,2888],{"class":73},"  {({ ",[33,2890,2799],{"class":77},[33,2892,81],{"class":73},[33,2894,2895],{"class":77},"toggle",[33,2897,317],{"class":73},[33,2899,320],{"class":65},[33,2901,113],{"class":73},[33,2903,2904,2906,2908,2910,2912,2915,2918,2921,2924,2927,2930,2932],{"class":35,"line":205},[33,2905,119],{"class":73},[33,2907,282],{"class":122},[33,2909,961],{"class":69},[33,2911,129],{"class":65},[33,2913,2914],{"class":73},"{toggle}>{on ",[33,2916,2917],{"class":65},"?",[33,2919,2920],{"class":132}," 'On'",[33,2922,2923],{"class":65}," :",[33,2925,2926],{"class":132}," 'Off'",[33,2928,2929],{"class":73},"}\u003C\u002F",[33,2931,282],{"class":122},[33,2933,136],{"class":73},[33,2935,2936],{"class":35,"line":215},[33,2937,2938],{"class":73},"  )}\n",[33,2940,2941,2943,2945],{"class":35,"line":221},[33,2942,1914],{"class":73},[33,2944,2881],{"class":438},[33,2946,136],{"class":73},[33,2948,2949],{"class":35,"line":227},[33,2950,59],{"emptyLinePlaceholder":58},[33,2952,2953],{"class":35,"line":232},[33,2954,2955],{"class":39},"\u002F\u002F NOTE: In modern React, custom hooks (useToggle) are usually preferred over\n",[33,2957,2958],{"class":35,"line":496},[33,2959,2960],{"class":39},"\u002F\u002F render props for reusable stateful logic. Render props remain valuable when\n",[33,2962,2963],{"class":35,"line":503},[33,2964,2965],{"class":39},"\u002F\u002F the logic is tightly coupled to a DOM element the component renders.\n",[180,2967,2969,2972],{"id":2968},"cloneelement-inject-props-into-an-existing-element",[30,2970,2971],{},"cloneElement"," — Inject Props Into an Existing Element",[19,2974,2976],{"filename":2975,"language":22},"clone_element.js",[24,2977,2979],{"className":26,"code":2978,"language":22,"meta":28,"style":28},"import { Children, cloneElement, isValidElement } from 'react'\n\n\u002F\u002F cloneElement lets a parent inject props into the elements it received as children.\n\u002F\u002F Common in compound components (next section) where the parent owns shared state\n\u002F\u002F and pushes it down into each child without the consumer wiring it manually.\n\nfunction RadioGroup({ name, value, onChange, children }) {\n  return (\n    \u003Cdiv role=\"radiogroup\">\n      {Children.map(children, (child) => {\n        if (!isValidElement(child)) return child  \u002F\u002F skip non-elements (strings, null)\n        return cloneElement(child, {\n          name,                                   \u002F\u002F inject shared name\n          checked: child.props.value === value,    \u002F\u002F inject checked state\n          onChange,                                \u002F\u002F inject shared handler\n        })\n      })}\n    \u003C\u002Fdiv>\n  )\n}\n\n\u002F\u002F Usage — consumer writes declarative JSX; RadioGroup wires the plumbing.\n\u003CRadioGroup name=\"plan\" value={selected} onChange={setSelected}>\n  \u003CRadio value=\"free\" label=\"Free\" \u002F>\n  \u003CRadio value=\"pro\" label=\"Pro\" \u002F>\n  \u003CRadio value=\"team\" label=\"Team\" \u002F>\n\u003C\u002FRadioGroup>\n",[30,2980,2981,2993,2997,3002,3007,3012,3016,3043,3049,3065,3083,3106,3117,3125,3139,3147,3152,3157,3165,3169,3173,3177,3182,3212,3236,3258,3280],{"__ignoreMap":28},[33,2982,2983,2985,2988,2990],{"class":35,"line":36},[33,2984,1522],{"class":65},[33,2986,2987],{"class":73}," { Children, cloneElement, isValidElement } ",[33,2989,1528],{"class":65},[33,2991,2992],{"class":132}," 'react'\n",[33,2994,2995],{"class":35,"line":43},[33,2996,59],{"emptyLinePlaceholder":58},[33,2998,2999],{"class":35,"line":49},[33,3000,3001],{"class":39},"\u002F\u002F cloneElement lets a parent inject props into the elements it received as children.\n",[33,3003,3004],{"class":35,"line":55},[33,3005,3006],{"class":39},"\u002F\u002F Common in compound components (next section) where the parent owns shared state\n",[33,3008,3009],{"class":35,"line":62},[33,3010,3011],{"class":39},"\u002F\u002F and pushes it down into each child without the consumer wiring it manually.\n",[33,3013,3014],{"class":35,"line":95},[33,3015,59],{"emptyLinePlaceholder":58},[33,3017,3018,3020,3023,3025,3027,3029,3032,3034,3037,3039,3041],{"class":35,"line":101},[33,3019,66],{"class":65},[33,3021,3022],{"class":69}," RadioGroup",[33,3024,74],{"class":73},[33,3026,78],{"class":77},[33,3028,81],{"class":73},[33,3030,3031],{"class":77},"value",[33,3033,81],{"class":73},[33,3035,3036],{"class":77},"onChange",[33,3038,81],{"class":73},[33,3040,2090],{"class":77},[33,3042,92],{"class":73},[33,3044,3045,3047],{"class":35,"line":107},[33,3046,110],{"class":65},[33,3048,113],{"class":73},[33,3050,3051,3053,3055,3058,3060,3063],{"class":35,"line":116},[33,3052,119],{"class":73},[33,3054,123],{"class":122},[33,3056,3057],{"class":69}," role",[33,3059,129],{"class":65},[33,3061,3062],{"class":132},"\"radiogroup\"",[33,3064,136],{"class":73},[33,3066,3067,3070,3072,3075,3077,3079,3081],{"class":35,"line":139},[33,3068,3069],{"class":73},"      {Children.",[33,3071,2320],{"class":69},[33,3073,3074],{"class":73},"(children, (",[33,3076,2325],{"class":77},[33,3078,1473],{"class":73},[33,3080,320],{"class":65},[33,3082,1619],{"class":73},[33,3084,3085,3088,3090,3092,3095,3098,3100,3103],{"class":35,"line":175},[33,3086,3087],{"class":65},"        if",[33,3089,427],{"class":73},[33,3091,430],{"class":65},[33,3093,3094],{"class":69},"isValidElement",[33,3096,3097],{"class":73},"(child)) ",[33,3099,276],{"class":65},[33,3101,3102],{"class":73}," child  ",[33,3104,3105],{"class":39},"\u002F\u002F skip non-elements (strings, null)\n",[33,3107,3108,3111,3114],{"class":35,"line":190},[33,3109,3110],{"class":65},"        return",[33,3112,3113],{"class":69}," cloneElement",[33,3115,3116],{"class":73},"(child, {\n",[33,3118,3119,3122],{"class":35,"line":205},[33,3120,3121],{"class":73},"          name,                                   ",[33,3123,3124],{"class":39},"\u002F\u002F inject shared name\n",[33,3126,3127,3130,3133,3136],{"class":35,"line":215},[33,3128,3129],{"class":73},"          checked: child.props.value ",[33,3131,3132],{"class":65},"===",[33,3134,3135],{"class":73}," value,    ",[33,3137,3138],{"class":39},"\u002F\u002F inject checked state\n",[33,3140,3141,3144],{"class":35,"line":221},[33,3142,3143],{"class":73},"          onChange,                                ",[33,3145,3146],{"class":39},"\u002F\u002F inject shared handler\n",[33,3148,3149],{"class":35,"line":227},[33,3150,3151],{"class":73},"        })\n",[33,3153,3154],{"class":35,"line":232},[33,3155,3156],{"class":73},"      })}\n",[33,3158,3159,3161,3163],{"class":35,"line":496},[33,3160,208],{"class":73},[33,3162,123],{"class":122},[33,3164,136],{"class":73},[33,3166,3167],{"class":35,"line":503},[33,3168,218],{"class":73},[33,3170,3171],{"class":35,"line":509},[33,3172,224],{"class":73},[33,3174,3175],{"class":35,"line":523},[33,3176,59],{"emptyLinePlaceholder":58},[33,3178,3179],{"class":35,"line":537},[33,3180,3181],{"class":39},"\u002F\u002F Usage — consumer writes declarative JSX; RadioGroup wires the plumbing.\n",[33,3183,3184,3186,3189,3192,3194,3197,3200,3202,3205,3207,3209],{"class":35,"line":543},[33,3185,947],{"class":73},[33,3187,3188],{"class":438},"RadioGroup",[33,3190,3191],{"class":69}," name",[33,3193,129],{"class":65},[33,3195,3196],{"class":132},"\"plan\"",[33,3198,3199],{"class":69}," value",[33,3201,129],{"class":65},[33,3203,3204],{"class":73},"{selected} ",[33,3206,3036],{"class":69},[33,3208,129],{"class":65},[33,3210,3211],{"class":73},"{setSelected}>\n",[33,3213,3214,3216,3219,3221,3223,3226,3228,3230,3233],{"class":35,"line":548},[33,3215,2230],{"class":73},[33,3217,3218],{"class":438},"Radio",[33,3220,3199],{"class":69},[33,3222,129],{"class":65},[33,3224,3225],{"class":132},"\"free\"",[33,3227,953],{"class":69},[33,3229,129],{"class":65},[33,3231,3232],{"class":132},"\"Free\"",[33,3234,3235],{"class":73}," \u002F>\n",[33,3237,3238,3240,3242,3244,3246,3249,3251,3253,3256],{"class":35,"line":1925},[33,3239,2230],{"class":73},[33,3241,3218],{"class":438},[33,3243,3199],{"class":69},[33,3245,129],{"class":65},[33,3247,3248],{"class":132},"\"pro\"",[33,3250,953],{"class":69},[33,3252,129],{"class":65},[33,3254,3255],{"class":132},"\"Pro\"",[33,3257,3235],{"class":73},[33,3259,3260,3262,3264,3266,3268,3271,3273,3275,3278],{"class":35,"line":1930},[33,3261,2230],{"class":73},[33,3263,3218],{"class":438},[33,3265,3199],{"class":69},[33,3267,129],{"class":65},[33,3269,3270],{"class":132},"\"team\"",[33,3272,953],{"class":69},[33,3274,129],{"class":65},[33,3276,3277],{"class":132},"\"Team\"",[33,3279,3235],{"class":73},[33,3281,3282,3284,3286],{"class":35,"line":1939},[33,3283,1914],{"class":73},[33,3285,3188],{"class":438},[33,3287,136],{"class":73},[14,3289,3291],{"id":3290},"component-composition-compound-components","Component Composition — Compound Components",[19,3293,3295],{"filename":3294,"language":22},"compound_components.js",[24,3296,3298],{"className":26,"code":3297,"language":22,"meta":28,"style":28},"\u002F\u002F Compound components: a set of parts that share implicit state via Context,\n\u002F\u002F exposing a declarative API without prop drilling. The consumer assembles the\n\u002F\u002F parts; the parent provides the coordination. This is how \u003Cselect>\u002F\u003Coption>,\n\u002F\u002F \u003CTabs>\u002F\u003CTab>, and most design-system APIs work.\n\nimport { createContext, useContext, useState } from 'react'\n\nconst TabsContext = createContext(null)\n\nfunction Tabs({ defaultValue, children }) {\n  const [active, setActive] = useState(defaultValue)\n  return (\n    \u003CTabsContext.Provider value={{ active, setActive }}>\n      \u003Cdiv className=\"tabs\">{children}\u003C\u002Fdiv>\n    \u003C\u002FTabsContext.Provider>\n  )\n}\n\nfunction TabList({ children }) {\n  return \u003Cdiv className=\"tab-list\" role=\"tablist\">{children}\u003C\u002Fdiv>\n}\n\nfunction Tab({ value, children }) {\n  const { active, setActive } = useContext(TabsContext)\n  return (\n    \u003Cbutton\n      role=\"tab\"\n      aria-selected={active === value}\n      onClick={() => setActive(value)}\n    >\n      {children}\n    \u003C\u002Fbutton>\n  )\n}\n\nfunction TabPanels({ children }) {\n  return \u003Cdiv className=\"tab-panels\">{children}\u003C\u002Fdiv>\n}\n\nfunction TabPanel({ value, children }) {\n  const { active } = useContext(TabsContext)\n  if (active !== value) return null\n  return \u003Cdiv role=\"tabpanel\">{children}\u003C\u002Fdiv>\n}\n\n\u002F\u002F Attach sub-components as static properties — the public API reads as a namespace.\nTabs.List = TabList\nTabs.Tab = Tab\nTabs.Panels = TabPanels\nTabs.Panel = TabPanel\n\n\u002F\u002F Usage — fully declarative, no prop drilling, consumer controls layout order.\n\u003CTabs defaultValue=\"overview\">\n  \u003CTabs.List>\n    \u003CTabs.Tab value=\"overview\">Overview\u003C\u002FTabs.Tab>\n    \u003CTabs.Tab value=\"activity\">Activity\u003C\u002FTabs.Tab>\n  \u003C\u002FTabs.List>\n  \u003CTabs.Panels>\n    \u003CTabs.Panel value=\"overview\">\u003COverview \u002F>\u003C\u002FTabs.Panel>\n    \u003CTabs.Panel value=\"activity\">\u003CActivity \u002F>\u003C\u002FTabs.Panel>\n  \u003C\u002FTabs.Panels>\n\u003C\u002FTabs>\n",[30,3299,3300,3305,3310,3315,3320,3324,3335,3339,3357,3361,3379,3402,3408,3422,3441,3449,3453,3457,3461,3474,3502,3506,3510,3527,3549,3555,3562,3572,3587,3606,3612,3618,3627,3632,3637,3642,3656,3678,3683,3688,3706,3723,3742,3764,3769,3774,3780,3791,3802,3813,3824,3829,3835,3853,3863,3884,3905,3915,3925,3952,3976,3985],{"__ignoreMap":28},[33,3301,3302],{"class":35,"line":36},[33,3303,3304],{"class":39},"\u002F\u002F Compound components: a set of parts that share implicit state via Context,\n",[33,3306,3307],{"class":35,"line":43},[33,3308,3309],{"class":39},"\u002F\u002F exposing a declarative API without prop drilling. The consumer assembles the\n",[33,3311,3312],{"class":35,"line":49},[33,3313,3314],{"class":39},"\u002F\u002F parts; the parent provides the coordination. This is how \u003Cselect>\u002F\u003Coption>,\n",[33,3316,3317],{"class":35,"line":55},[33,3318,3319],{"class":39},"\u002F\u002F \u003CTabs>\u002F\u003CTab>, and most design-system APIs work.\n",[33,3321,3322],{"class":35,"line":62},[33,3323,59],{"emptyLinePlaceholder":58},[33,3325,3326,3328,3331,3333],{"class":35,"line":95},[33,3327,1522],{"class":65},[33,3329,3330],{"class":73}," { createContext, useContext, useState } ",[33,3332,1528],{"class":65},[33,3334,2992],{"class":132},[33,3336,3337],{"class":35,"line":101},[33,3338,59],{"emptyLinePlaceholder":58},[33,3340,3341,3343,3346,3348,3351,3353,3355],{"class":35,"line":107},[33,3342,304],{"class":65},[33,3344,3345],{"class":438}," TabsContext",[33,3347,309],{"class":65},[33,3349,3350],{"class":69}," createContext",[33,3352,577],{"class":73},[33,3354,1011],{"class":438},[33,3356,2818],{"class":73},[33,3358,3359],{"class":35,"line":116},[33,3360,59],{"emptyLinePlaceholder":58},[33,3362,3363,3365,3368,3370,3373,3375,3377],{"class":35,"line":139},[33,3364,66],{"class":65},[33,3366,3367],{"class":69}," Tabs",[33,3369,74],{"class":73},[33,3371,3372],{"class":77},"defaultValue",[33,3374,81],{"class":73},[33,3376,2090],{"class":77},[33,3378,92],{"class":73},[33,3380,3381,3383,3385,3388,3390,3393,3395,3397,3399],{"class":35,"line":175},[33,3382,1167],{"class":65},[33,3384,2571],{"class":73},[33,3386,3387],{"class":438},"active",[33,3389,81],{"class":73},[33,3391,3392],{"class":438},"setActive",[33,3394,2582],{"class":73},[33,3396,129],{"class":65},[33,3398,2587],{"class":69},[33,3400,3401],{"class":73},"(defaultValue)\n",[33,3403,3404,3406],{"class":35,"line":190},[33,3405,110],{"class":65},[33,3407,113],{"class":73},[33,3409,3410,3412,3415,3417,3419],{"class":35,"line":205},[33,3411,119],{"class":73},[33,3413,3414],{"class":438},"TabsContext.Provider",[33,3416,3199],{"class":69},[33,3418,129],{"class":65},[33,3420,3421],{"class":73},"{{ active, setActive }}>\n",[33,3423,3424,3426,3428,3430,3432,3435,3437,3439],{"class":35,"line":215},[33,3425,142],{"class":73},[33,3427,123],{"class":122},[33,3429,126],{"class":69},[33,3431,129],{"class":65},[33,3433,3434],{"class":132},"\"tabs\"",[33,3436,2184],{"class":73},[33,3438,123],{"class":122},[33,3440,136],{"class":73},[33,3442,3443,3445,3447],{"class":35,"line":221},[33,3444,208],{"class":73},[33,3446,3414],{"class":438},[33,3448,136],{"class":73},[33,3450,3451],{"class":35,"line":227},[33,3452,218],{"class":73},[33,3454,3455],{"class":35,"line":232},[33,3456,224],{"class":73},[33,3458,3459],{"class":35,"line":496},[33,3460,59],{"emptyLinePlaceholder":58},[33,3462,3463,3465,3468,3470,3472],{"class":35,"line":503},[33,3464,66],{"class":65},[33,3466,3467],{"class":69}," TabList",[33,3469,74],{"class":73},[33,3471,2090],{"class":77},[33,3473,92],{"class":73},[33,3475,3476,3478,3480,3482,3484,3486,3489,3491,3493,3496,3498,3500],{"class":35,"line":509},[33,3477,110],{"class":65},[33,3479,279],{"class":73},[33,3481,123],{"class":122},[33,3483,126],{"class":69},[33,3485,129],{"class":65},[33,3487,3488],{"class":132},"\"tab-list\"",[33,3490,3057],{"class":69},[33,3492,129],{"class":65},[33,3494,3495],{"class":132},"\"tablist\"",[33,3497,2184],{"class":73},[33,3499,123],{"class":122},[33,3501,136],{"class":73},[33,3503,3504],{"class":35,"line":523},[33,3505,224],{"class":73},[33,3507,3508],{"class":35,"line":537},[33,3509,59],{"emptyLinePlaceholder":58},[33,3511,3512,3514,3517,3519,3521,3523,3525],{"class":35,"line":543},[33,3513,66],{"class":65},[33,3515,3516],{"class":69}," Tab",[33,3518,74],{"class":73},[33,3520,3031],{"class":77},[33,3522,81],{"class":73},[33,3524,2090],{"class":77},[33,3526,92],{"class":73},[33,3528,3529,3531,3533,3535,3537,3539,3541,3543,3546],{"class":35,"line":548},[33,3530,1167],{"class":65},[33,3532,1993],{"class":73},[33,3534,3387],{"class":438},[33,3536,81],{"class":73},[33,3538,3392],{"class":438},[33,3540,2050],{"class":73},[33,3542,129],{"class":65},[33,3544,3545],{"class":69}," useContext",[33,3547,3548],{"class":73},"(TabsContext)\n",[33,3550,3551,3553],{"class":35,"line":1925},[33,3552,110],{"class":65},[33,3554,113],{"class":73},[33,3556,3557,3559],{"class":35,"line":1930},[33,3558,119],{"class":73},[33,3560,3561],{"class":122},"button\n",[33,3563,3564,3567,3569],{"class":35,"line":1939},[33,3565,3566],{"class":69},"      role",[33,3568,129],{"class":65},[33,3570,3571],{"class":132},"\"tab\"\n",[33,3573,3574,3577,3579,3582,3584],{"class":35,"line":1948},[33,3575,3576],{"class":69},"      aria-selected",[33,3578,129],{"class":65},[33,3580,3581],{"class":73},"{active ",[33,3583,3132],{"class":65},[33,3585,3586],{"class":73}," value}\n",[33,3588,3590,3593,3595,3598,3600,3603],{"class":35,"line":3589},29,[33,3591,3592],{"class":69},"      onClick",[33,3594,129],{"class":65},[33,3596,3597],{"class":73},"{() ",[33,3599,320],{"class":65},[33,3601,3602],{"class":69}," setActive",[33,3604,3605],{"class":73},"(value)}\n",[33,3607,3609],{"class":35,"line":3608},30,[33,3610,3611],{"class":73},"    >\n",[33,3613,3615],{"class":35,"line":3614},31,[33,3616,3617],{"class":73},"      {children}\n",[33,3619,3621,3623,3625],{"class":35,"line":3620},32,[33,3622,208],{"class":73},[33,3624,282],{"class":122},[33,3626,136],{"class":73},[33,3628,3630],{"class":35,"line":3629},33,[33,3631,218],{"class":73},[33,3633,3635],{"class":35,"line":3634},34,[33,3636,224],{"class":73},[33,3638,3640],{"class":35,"line":3639},35,[33,3641,59],{"emptyLinePlaceholder":58},[33,3643,3645,3647,3650,3652,3654],{"class":35,"line":3644},36,[33,3646,66],{"class":65},[33,3648,3649],{"class":69}," TabPanels",[33,3651,74],{"class":73},[33,3653,2090],{"class":77},[33,3655,92],{"class":73},[33,3657,3659,3661,3663,3665,3667,3669,3672,3674,3676],{"class":35,"line":3658},37,[33,3660,110],{"class":65},[33,3662,279],{"class":73},[33,3664,123],{"class":122},[33,3666,126],{"class":69},[33,3668,129],{"class":65},[33,3670,3671],{"class":132},"\"tab-panels\"",[33,3673,2184],{"class":73},[33,3675,123],{"class":122},[33,3677,136],{"class":73},[33,3679,3681],{"class":35,"line":3680},38,[33,3682,224],{"class":73},[33,3684,3686],{"class":35,"line":3685},39,[33,3687,59],{"emptyLinePlaceholder":58},[33,3689,3691,3693,3696,3698,3700,3702,3704],{"class":35,"line":3690},40,[33,3692,66],{"class":65},[33,3694,3695],{"class":69}," TabPanel",[33,3697,74],{"class":73},[33,3699,3031],{"class":77},[33,3701,81],{"class":73},[33,3703,2090],{"class":77},[33,3705,92],{"class":73},[33,3707,3709,3711,3713,3715,3717,3719,3721],{"class":35,"line":3708},41,[33,3710,1167],{"class":65},[33,3712,1993],{"class":73},[33,3714,3387],{"class":438},[33,3716,2050],{"class":73},[33,3718,129],{"class":65},[33,3720,3545],{"class":69},[33,3722,3548],{"class":73},[33,3724,3726,3728,3731,3734,3737,3739],{"class":35,"line":3725},42,[33,3727,424],{"class":65},[33,3729,3730],{"class":73}," (active ",[33,3732,3733],{"class":65},"!==",[33,3735,3736],{"class":73}," value) ",[33,3738,276],{"class":65},[33,3740,3741],{"class":438}," null\n",[33,3743,3745,3747,3749,3751,3753,3755,3758,3760,3762],{"class":35,"line":3744},43,[33,3746,110],{"class":65},[33,3748,279],{"class":73},[33,3750,123],{"class":122},[33,3752,3057],{"class":69},[33,3754,129],{"class":65},[33,3756,3757],{"class":132},"\"tabpanel\"",[33,3759,2184],{"class":73},[33,3761,123],{"class":122},[33,3763,136],{"class":73},[33,3765,3767],{"class":35,"line":3766},44,[33,3768,224],{"class":73},[33,3770,3772],{"class":35,"line":3771},45,[33,3773,59],{"emptyLinePlaceholder":58},[33,3775,3777],{"class":35,"line":3776},46,[33,3778,3779],{"class":39},"\u002F\u002F Attach sub-components as static properties — the public API reads as a namespace.\n",[33,3781,3783,3786,3788],{"class":35,"line":3782},47,[33,3784,3785],{"class":73},"Tabs.List ",[33,3787,129],{"class":65},[33,3789,3790],{"class":73}," TabList\n",[33,3792,3794,3797,3799],{"class":35,"line":3793},48,[33,3795,3796],{"class":73},"Tabs.Tab ",[33,3798,129],{"class":65},[33,3800,3801],{"class":73}," Tab\n",[33,3803,3805,3808,3810],{"class":35,"line":3804},49,[33,3806,3807],{"class":73},"Tabs.Panels ",[33,3809,129],{"class":65},[33,3811,3812],{"class":73}," TabPanels\n",[33,3814,3816,3819,3821],{"class":35,"line":3815},50,[33,3817,3818],{"class":73},"Tabs.Panel ",[33,3820,129],{"class":65},[33,3822,3823],{"class":73}," TabPanel\n",[33,3825,3827],{"class":35,"line":3826},51,[33,3828,59],{"emptyLinePlaceholder":58},[33,3830,3832],{"class":35,"line":3831},52,[33,3833,3834],{"class":39},"\u002F\u002F Usage — fully declarative, no prop drilling, consumer controls layout order.\n",[33,3836,3838,3840,3843,3846,3848,3851],{"class":35,"line":3837},53,[33,3839,947],{"class":73},[33,3841,3842],{"class":438},"Tabs",[33,3844,3845],{"class":69}," defaultValue",[33,3847,129],{"class":65},[33,3849,3850],{"class":132},"\"overview\"",[33,3852,136],{"class":73},[33,3854,3856,3858,3861],{"class":35,"line":3855},54,[33,3857,2230],{"class":73},[33,3859,3860],{"class":438},"Tabs.List",[33,3862,136],{"class":73},[33,3864,3866,3868,3871,3873,3875,3877,3880,3882],{"class":35,"line":3865},55,[33,3867,119],{"class":73},[33,3869,3870],{"class":438},"Tabs.Tab",[33,3872,3199],{"class":69},[33,3874,129],{"class":65},[33,3876,3850],{"class":132},[33,3878,3879],{"class":73},">Overview\u003C\u002F",[33,3881,3870],{"class":438},[33,3883,136],{"class":73},[33,3885,3887,3889,3891,3893,3895,3898,3901,3903],{"class":35,"line":3886},56,[33,3888,119],{"class":73},[33,3890,3870],{"class":438},[33,3892,3199],{"class":69},[33,3894,129],{"class":65},[33,3896,3897],{"class":132},"\"activity\"",[33,3899,3900],{"class":73},">Activity\u003C\u002F",[33,3902,3870],{"class":438},[33,3904,136],{"class":73},[33,3906,3908,3911,3913],{"class":35,"line":3907},57,[33,3909,3910],{"class":73},"  \u003C\u002F",[33,3912,3860],{"class":438},[33,3914,136],{"class":73},[33,3916,3918,3920,3923],{"class":35,"line":3917},58,[33,3919,2230],{"class":73},[33,3921,3922],{"class":438},"Tabs.Panels",[33,3924,136],{"class":73},[33,3926,3928,3930,3933,3935,3937,3939,3942,3945,3948,3950],{"class":35,"line":3927},59,[33,3929,119],{"class":73},[33,3931,3932],{"class":438},"Tabs.Panel",[33,3934,3199],{"class":69},[33,3936,129],{"class":65},[33,3938,3850],{"class":132},[33,3940,3941],{"class":73},">\u003C",[33,3943,3944],{"class":438},"Overview",[33,3946,3947],{"class":73}," \u002F>\u003C\u002F",[33,3949,3932],{"class":438},[33,3951,136],{"class":73},[33,3953,3955,3957,3959,3961,3963,3965,3967,3970,3972,3974],{"class":35,"line":3954},60,[33,3956,119],{"class":73},[33,3958,3932],{"class":438},[33,3960,3199],{"class":69},[33,3962,129],{"class":65},[33,3964,3897],{"class":132},[33,3966,3941],{"class":73},[33,3968,3969],{"class":438},"Activity",[33,3971,3947],{"class":73},[33,3973,3932],{"class":438},[33,3975,136],{"class":73},[33,3977,3979,3981,3983],{"class":35,"line":3978},61,[33,3980,3910],{"class":73},[33,3982,3922],{"class":438},[33,3984,136],{"class":73},[33,3986,3988,3990,3992],{"class":35,"line":3987},62,[33,3989,1914],{"class":73},[33,3991,3842],{"class":438},[33,3993,136],{"class":73},[14,3995,3997],{"id":3996},"anti-patterns","Anti-Patterns",[180,3999,4001],{"id":4000},"prop-drilling-forwarding-through-layers-that-dont-use-it","Prop Drilling — Forwarding Through Layers That Don't Use It",[19,4003,4005],{"filename":4004,"language":22},"prop_drilling.js",[24,4006,4008],{"className":26,"code":4007,"language":22,"meta":28,"style":28},"\u002F\u002F `theme` is only consumed by ThemedButton, but every intermediate component\n\u002F\u002F must accept and forward it. Each layer gains an irrelevant prop, and the\n\u002F\u002F coupling grows with every hop. Fine for 1-2 levels; a liability past 3-4.\n\nfunction App() {\n  const [theme] = useState('dark')\n  return \u003CPage theme={theme} \u002F>\n}\nfunction Page({ theme }) {\n  return \u003CSidebar theme={theme} \u002F>  \u002F\u002F Page doesn't use theme, just forwards\n}\nfunction Sidebar({ theme }) {\n  return \u003CUserPanel theme={theme} \u002F>  \u002F\u002F Sidebar doesn't use theme either\n}\nfunction UserPanel({ theme }) {\n  return \u003CThemedButton theme={theme} \u002F>  \u002F\u002F only ThemedButton actually needs it\n}\nfunction ThemedButton({ theme }) {\n  return \u003Cbutton className={`btn btn--${theme}`}>Click\u003C\u002Fbutton>\n}\n\n\u002F\u002F FIXES (covered in depth later):\n\u002F\u002F   Context (Ch 7)      — broadcast a value to any descendant without forwarding.\n\u002F\u002F   Composition (Ch 15) — pass the already-built \u003CThemedButton \u002F> element down,\n\u002F\u002F                         so intermediates never see `theme` at all.\n",[30,4009,4010,4015,4020,4025,4029,4038,4060,4077,4081,4094,4113,4117,4130,4148,4152,4165,4183,4187,4200,4227,4231,4235,4240,4245,4250],{"__ignoreMap":28},[33,4011,4012],{"class":35,"line":36},[33,4013,4014],{"class":39},"\u002F\u002F `theme` is only consumed by ThemedButton, but every intermediate component\n",[33,4016,4017],{"class":35,"line":43},[33,4018,4019],{"class":39},"\u002F\u002F must accept and forward it. Each layer gains an irrelevant prop, and the\n",[33,4021,4022],{"class":35,"line":49},[33,4023,4024],{"class":39},"\u002F\u002F coupling grows with every hop. Fine for 1-2 levels; a liability past 3-4.\n",[33,4026,4027],{"class":35,"line":55},[33,4028,59],{"emptyLinePlaceholder":58},[33,4030,4031,4033,4036],{"class":35,"line":62},[33,4032,66],{"class":65},[33,4034,4035],{"class":69}," App",[33,4037,493],{"class":73},[33,4039,4040,4042,4044,4047,4049,4051,4053,4055,4058],{"class":35,"line":95},[33,4041,1167],{"class":65},[33,4043,2571],{"class":73},[33,4045,4046],{"class":438},"theme",[33,4048,2582],{"class":73},[33,4050,129],{"class":65},[33,4052,2587],{"class":69},[33,4054,577],{"class":73},[33,4056,4057],{"class":132},"'dark'",[33,4059,2818],{"class":73},[33,4061,4062,4064,4066,4069,4072,4074],{"class":35,"line":101},[33,4063,110],{"class":65},[33,4065,279],{"class":73},[33,4067,4068],{"class":438},"Page",[33,4070,4071],{"class":69}," theme",[33,4073,129],{"class":65},[33,4075,4076],{"class":73},"{theme} \u002F>\n",[33,4078,4079],{"class":35,"line":107},[33,4080,224],{"class":73},[33,4082,4083,4085,4088,4090,4092],{"class":35,"line":116},[33,4084,66],{"class":65},[33,4086,4087],{"class":69}," Page",[33,4089,74],{"class":73},[33,4091,4046],{"class":77},[33,4093,92],{"class":73},[33,4095,4096,4098,4100,4103,4105,4107,4110],{"class":35,"line":139},[33,4097,110],{"class":65},[33,4099,279],{"class":73},[33,4101,4102],{"class":438},"Sidebar",[33,4104,4071],{"class":69},[33,4106,129],{"class":65},[33,4108,4109],{"class":73},"{theme} \u002F>  ",[33,4111,4112],{"class":39},"\u002F\u002F Page doesn't use theme, just forwards\n",[33,4114,4115],{"class":35,"line":175},[33,4116,224],{"class":73},[33,4118,4119,4121,4124,4126,4128],{"class":35,"line":190},[33,4120,66],{"class":65},[33,4122,4123],{"class":69}," Sidebar",[33,4125,74],{"class":73},[33,4127,4046],{"class":77},[33,4129,92],{"class":73},[33,4131,4132,4134,4136,4139,4141,4143,4145],{"class":35,"line":205},[33,4133,110],{"class":65},[33,4135,279],{"class":73},[33,4137,4138],{"class":438},"UserPanel",[33,4140,4071],{"class":69},[33,4142,129],{"class":65},[33,4144,4109],{"class":73},[33,4146,4147],{"class":39},"\u002F\u002F Sidebar doesn't use theme either\n",[33,4149,4150],{"class":35,"line":215},[33,4151,224],{"class":73},[33,4153,4154,4156,4159,4161,4163],{"class":35,"line":221},[33,4155,66],{"class":65},[33,4157,4158],{"class":69}," UserPanel",[33,4160,74],{"class":73},[33,4162,4046],{"class":77},[33,4164,92],{"class":73},[33,4166,4167,4169,4171,4174,4176,4178,4180],{"class":35,"line":227},[33,4168,110],{"class":65},[33,4170,279],{"class":73},[33,4172,4173],{"class":438},"ThemedButton",[33,4175,4071],{"class":69},[33,4177,129],{"class":65},[33,4179,4109],{"class":73},[33,4181,4182],{"class":39},"\u002F\u002F only ThemedButton actually needs it\n",[33,4184,4185],{"class":35,"line":232},[33,4186,224],{"class":73},[33,4188,4189,4191,4194,4196,4198],{"class":35,"line":496},[33,4190,66],{"class":65},[33,4192,4193],{"class":69}," ThemedButton",[33,4195,74],{"class":73},[33,4197,4046],{"class":77},[33,4199,92],{"class":73},[33,4201,4202,4204,4206,4208,4210,4212,4214,4216,4218,4220,4223,4225],{"class":35,"line":503},[33,4203,110],{"class":65},[33,4205,279],{"class":73},[33,4207,282],{"class":122},[33,4209,126],{"class":69},[33,4211,129],{"class":65},[33,4213,161],{"class":73},[33,4215,896],{"class":132},[33,4217,4046],{"class":73},[33,4219,901],{"class":132},[33,4221,4222],{"class":73},"}>Click\u003C\u002F",[33,4224,282],{"class":122},[33,4226,136],{"class":73},[33,4228,4229],{"class":35,"line":509},[33,4230,224],{"class":73},[33,4232,4233],{"class":35,"line":523},[33,4234,59],{"emptyLinePlaceholder":58},[33,4236,4237],{"class":35,"line":537},[33,4238,4239],{"class":39},"\u002F\u002F FIXES (covered in depth later):\n",[33,4241,4242],{"class":35,"line":543},[33,4243,4244],{"class":39},"\u002F\u002F   Context (Ch 7)      — broadcast a value to any descendant without forwarding.\n",[33,4246,4247],{"class":35,"line":548},[33,4248,4249],{"class":39},"\u002F\u002F   Composition (Ch 15) — pass the already-built \u003CThemedButton \u002F> element down,\n",[33,4251,4252],{"class":35,"line":1925},[33,4253,4254],{"class":39},"\u002F\u002F                         so intermediates never see `theme` at all.\n",[180,4256,4258],{"id":4257},"prop-mutation-silently-corrupts-the-owner","Prop Mutation — Silently Corrupts the Owner",[19,4260,4262],{"filename":4261,"language":22},"prop_mutation.js",[24,4263,4265],{"className":26,"code":4264,"language":22,"meta":28,"style":28},"\u002F\u002F ANTI-PATTERN: mutating an object\u002Farray prop in place.\n\u002F\u002F The parent owns the state; the child has no right to mutate it.\n\u002F\u002F Objects are references — your mutation leaks to every component holding that ref.\n\nfunction TodoList({ todos }) {\n  todos.push({ id: Date.now(), text: 'New' })  \u002F\u002F ← mutates parent's array\n  return todos.map(t => \u003Cli key={t.id}>{t.text}\u003C\u002Fli>)\n  \u002F\u002F Parent's array is now longer, but React didn't see a new reference →\n  \u002F\u002F parent may not re-render, and other consumers of `todos` see ghost items.\n}\n",[30,4266,4267,4272,4277,4282,4286,4300,4326,4359,4364,4369],{"__ignoreMap":28},[33,4268,4269],{"class":35,"line":36},[33,4270,4271],{"class":39},"\u002F\u002F ANTI-PATTERN: mutating an object\u002Farray prop in place.\n",[33,4273,4274],{"class":35,"line":43},[33,4275,4276],{"class":39},"\u002F\u002F The parent owns the state; the child has no right to mutate it.\n",[33,4278,4279],{"class":35,"line":49},[33,4280,4281],{"class":39},"\u002F\u002F Objects are references — your mutation leaks to every component holding that ref.\n",[33,4283,4284],{"class":35,"line":55},[33,4285,59],{"emptyLinePlaceholder":58},[33,4287,4288,4290,4293,4295,4298],{"class":35,"line":62},[33,4289,66],{"class":65},[33,4291,4292],{"class":69}," TodoList",[33,4294,74],{"class":73},[33,4296,4297],{"class":77},"todos",[33,4299,92],{"class":73},[33,4301,4302,4305,4308,4311,4314,4317,4320,4323],{"class":35,"line":95},[33,4303,4304],{"class":73},"  todos.",[33,4306,4307],{"class":69},"push",[33,4309,4310],{"class":73},"({ id: Date.",[33,4312,4313],{"class":69},"now",[33,4315,4316],{"class":73},"(), text: ",[33,4318,4319],{"class":132},"'New'",[33,4321,4322],{"class":73}," })  ",[33,4324,4325],{"class":39},"\u002F\u002F ← mutates parent's array\n",[33,4327,4328,4330,4333,4335,4337,4340,4342,4344,4347,4349,4351,4354,4356],{"class":35,"line":101},[33,4329,110],{"class":65},[33,4331,4332],{"class":73}," todos.",[33,4334,2320],{"class":69},[33,4336,577],{"class":73},[33,4338,4339],{"class":77},"t",[33,4341,2328],{"class":65},[33,4343,279],{"class":73},[33,4345,4346],{"class":122},"li",[33,4348,2335],{"class":69},[33,4350,129],{"class":65},[33,4352,4353],{"class":73},"{t.id}>{t.text}\u003C\u002F",[33,4355,4346],{"class":122},[33,4357,4358],{"class":73},">)\n",[33,4360,4361],{"class":35,"line":107},[33,4362,4363],{"class":39},"  \u002F\u002F Parent's array is now longer, but React didn't see a new reference →\n",[33,4365,4366],{"class":35,"line":116},[33,4367,4368],{"class":39},"  \u002F\u002F parent may not re-render, and other consumers of `todos` see ghost items.\n",[33,4370,4371],{"class":35,"line":139},[33,4372,224],{"class":73},[180,4374,4376],{"id":4375},"boolean-prop-explosion-unmanageable-combinatorics","Boolean Prop Explosion — Unmanageable Combinatorics",[19,4378,4380],{"filename":4379,"language":22},"boolean_prop_explosion.js",[24,4381,4383],{"className":26,"code":4382,"language":22,"meta":28,"style":28},"\u002F\u002F ANTI-PATTERN: a forest of boolean flags that combine into invalid states.\n\u002F\u002F `isLoading && isError` is nonsensical but the API allows it.\n\u002F\u002F Every new flag doubles the number of possible combinations to reason about.\n\nfunction Banner({ isLoading, isError, isEmpty, isSuccess, children }) {\n  if (isLoading) return \u003CSpinner \u002F>\n  if (isError) return \u003CErrorView \u002F>\n  if (isEmpty) return \u003CEmptyView \u002F>\n  return \u003Cdiv>{children}\u003C\u002Fdiv>  \u002F\u002F what if isLoading AND isError are both true?\n}\n\n\u002F\u002F FIX: a single discriminated union prop (see next section) — mutually exclusive\n\u002F\u002F states are structurally impossible, not just conventionally avoided.\n",[30,4384,4385,4390,4395,4400,4404,4437,4453,4469,4485,4502,4506,4510,4515],{"__ignoreMap":28},[33,4386,4387],{"class":35,"line":36},[33,4388,4389],{"class":39},"\u002F\u002F ANTI-PATTERN: a forest of boolean flags that combine into invalid states.\n",[33,4391,4392],{"class":35,"line":43},[33,4393,4394],{"class":39},"\u002F\u002F `isLoading && isError` is nonsensical but the API allows it.\n",[33,4396,4397],{"class":35,"line":49},[33,4398,4399],{"class":39},"\u002F\u002F Every new flag doubles the number of possible combinations to reason about.\n",[33,4401,4402],{"class":35,"line":55},[33,4403,59],{"emptyLinePlaceholder":58},[33,4405,4406,4408,4411,4413,4416,4418,4421,4423,4426,4428,4431,4433,4435],{"class":35,"line":62},[33,4407,66],{"class":65},[33,4409,4410],{"class":69}," Banner",[33,4412,74],{"class":73},[33,4414,4415],{"class":77},"isLoading",[33,4417,81],{"class":73},[33,4419,4420],{"class":77},"isError",[33,4422,81],{"class":73},[33,4424,4425],{"class":77},"isEmpty",[33,4427,81],{"class":73},[33,4429,4430],{"class":77},"isSuccess",[33,4432,81],{"class":73},[33,4434,2090],{"class":77},[33,4436,92],{"class":73},[33,4438,4439,4441,4444,4446,4448,4451],{"class":35,"line":95},[33,4440,424],{"class":65},[33,4442,4443],{"class":73}," (isLoading) ",[33,4445,276],{"class":65},[33,4447,279],{"class":73},[33,4449,4450],{"class":438},"Spinner",[33,4452,3235],{"class":73},[33,4454,4455,4457,4460,4462,4464,4467],{"class":35,"line":101},[33,4456,424],{"class":65},[33,4458,4459],{"class":73}," (isError) ",[33,4461,276],{"class":65},[33,4463,279],{"class":73},[33,4465,4466],{"class":438},"ErrorView",[33,4468,3235],{"class":73},[33,4470,4471,4473,4476,4478,4480,4483],{"class":35,"line":107},[33,4472,424],{"class":65},[33,4474,4475],{"class":73}," (isEmpty) ",[33,4477,276],{"class":65},[33,4479,279],{"class":73},[33,4481,4482],{"class":438},"EmptyView",[33,4484,3235],{"class":73},[33,4486,4487,4489,4491,4493,4495,4497,4499],{"class":35,"line":116},[33,4488,110],{"class":65},[33,4490,279],{"class":73},[33,4492,123],{"class":122},[33,4494,2184],{"class":73},[33,4496,123],{"class":122},[33,4498,717],{"class":73},[33,4500,4501],{"class":39},"\u002F\u002F what if isLoading AND isError are both true?\n",[33,4503,4504],{"class":35,"line":139},[33,4505,224],{"class":73},[33,4507,4508],{"class":35,"line":175},[33,4509,59],{"emptyLinePlaceholder":58},[33,4511,4512],{"class":35,"line":190},[33,4513,4514],{"class":39},"\u002F\u002F FIX: a single discriminated union prop (see next section) — mutually exclusive\n",[33,4516,4517],{"class":35,"line":205},[33,4518,4519],{"class":39},"\u002F\u002F states are structurally impossible, not just conventionally avoided.\n",[14,4521,4523],{"id":4522},"production-pattern-typed-component-with-discriminated-union-props","Production Pattern: Typed Component with Discriminated Union Props",[19,4525,4527],{"filename":4526,"language":1688},"discriminated_union.ts",[24,4528,4530],{"className":1691,"code":4529,"language":1688,"meta":28,"style":28},"import { useState } from 'react'\n\n\u002F\u002F A discriminated union makes invalid states unrepresentable at compile time.\n\u002F\u002F The `status` field is the discriminant; each variant has its own payload shape.\n\ntype AsyncResultProps\u003CT> =\n  | { status: 'idle' }\n  | { status: 'loading' }\n  | { status: 'error'; error: Error; onRetry: () => void }\n  | { status: 'success'; data: T; onRefresh: () => void }\n\nfunction AsyncResult\u003CT>({ status, ...rest }: AsyncResultProps\u003CT>) {\n  switch (status) {\n    case 'idle':\n      return \u003Cp className=\"muted\">Nothing loaded yet.\u003C\u002Fp>\n    case 'loading':\n      return \u003CSpinner \u002F>\n    case 'error': {\n      \u002F\u002F TS narrows `rest` to { error, onRetry } here — accessing rest.data\n      \u002F\u002F would be a compile error. Invalid combinations are impossible.\n      const { error, onRetry } = rest\n      return (\n        \u003Cdiv className=\"error\">\n          \u003Cp>{error.message}\u003C\u002Fp>\n          \u003Cbutton onClick={onRetry}>Retry\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      )\n    }\n    case 'success': {\n      const { data, onRefresh } = rest\n      return (\n        \u003Cdiv>\n          \u003Cpre>{JSON.stringify(data, null, 2)}\u003C\u002Fpre>\n          \u003Cbutton onClick={onRefresh}>Refresh\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      )\n    }\n  }\n}\n\n\u002F\u002F USAGE — TS enforces the correct payload for each variant.\n\u003CAsyncResult status=\"idle\" \u002F>\n\u003CAsyncResult status=\"loading\" \u002F>\n\u003CAsyncResult\n  status=\"error\"\n  error={new Error('Network failed')}\n  onRetry={refetch}\n\u002F>\n\u003CAsyncResult status=\"success\" data={result} onRefresh={refetch} \u002F>\n\n\u002F\u002F WRONG (compile error): \u003CAsyncResult status=\"error\" \u002F>      \u002F\u002F missing error, onRetry\n\u002F\u002F WRONG (compile error): \u003CAsyncResult status=\"success\" data={x} \u002F>  \u002F\u002F missing onRefresh\n",[30,4531,4532,4543,4547,4552,4557,4561,4579,4596,4611,4651,4689,4693,4728,4736,4746,4771,4779,4789,4794,4799,4804,4809,4814,4829,4845,4869,4878,4883,4888,4897,4902,4908,4916,4949,4973,4981,4985,4989,4994,4998,5002,5007,5021,5034,5041,5051,5072,5082,5087,5113,5117,5125],{"__ignoreMap":28},[33,4533,4534,4536,4539,4541],{"class":35,"line":36},[33,4535,1522],{"class":65},[33,4537,4538],{"class":73}," { useState } ",[33,4540,1528],{"class":65},[33,4542,2992],{"class":132},[33,4544,4545],{"class":35,"line":43},[33,4546,59],{"emptyLinePlaceholder":58},[33,4548,4549],{"class":35,"line":49},[33,4550,4551],{"class":39},"\u002F\u002F A discriminated union makes invalid states unrepresentable at compile time.\n",[33,4553,4554],{"class":35,"line":55},[33,4555,4556],{"class":39},"\u002F\u002F The `status` field is the discriminant; each variant has its own payload shape.\n",[33,4558,4559],{"class":35,"line":62},[33,4560,59],{"emptyLinePlaceholder":58},[33,4562,4563,4565,4568,4570,4573,4576],{"class":35,"line":95},[33,4564,1957],{"class":65},[33,4566,4567],{"class":69}," AsyncResultProps",[33,4569,947],{"class":73},[33,4571,4572],{"class":69},"T",[33,4574,4575],{"class":73},"> ",[33,4577,4578],{"class":65},"=\n",[33,4580,4581,4584,4586,4589,4591,4594],{"class":35,"line":101},[33,4582,4583],{"class":65},"  |",[33,4585,1993],{"class":73},[33,4587,4588],{"class":77},"status",[33,4590,1731],{"class":65},[33,4592,4593],{"class":132}," 'idle'",[33,4595,2008],{"class":73},[33,4597,4598,4600,4602,4604,4606,4609],{"class":35,"line":107},[33,4599,4583],{"class":65},[33,4601,1993],{"class":73},[33,4603,4588],{"class":77},[33,4605,1731],{"class":65},[33,4607,4608],{"class":132}," 'loading'",[33,4610,2008],{"class":73},[33,4612,4613,4615,4617,4619,4621,4624,4627,4630,4632,4635,4637,4640,4642,4644,4646,4649],{"class":35,"line":116},[33,4614,4583],{"class":65},[33,4616,1993],{"class":73},[33,4618,4588],{"class":77},[33,4620,1731],{"class":65},[33,4622,4623],{"class":132}," 'error'",[33,4625,4626],{"class":73},"; ",[33,4628,4629],{"class":77},"error",[33,4631,1731],{"class":65},[33,4633,4634],{"class":69}," Error",[33,4636,4626],{"class":73},[33,4638,4639],{"class":69},"onRetry",[33,4641,1731],{"class":65},[33,4643,2830],{"class":73},[33,4645,320],{"class":65},[33,4647,4648],{"class":438}," void",[33,4650,2008],{"class":73},[33,4652,4653,4655,4657,4659,4661,4664,4666,4669,4671,4674,4676,4679,4681,4683,4685,4687],{"class":35,"line":139},[33,4654,4583],{"class":65},[33,4656,1993],{"class":73},[33,4658,4588],{"class":77},[33,4660,1731],{"class":65},[33,4662,4663],{"class":132}," 'success'",[33,4665,4626],{"class":73},[33,4667,4668],{"class":77},"data",[33,4670,1731],{"class":65},[33,4672,4673],{"class":69}," T",[33,4675,4626],{"class":73},[33,4677,4678],{"class":69},"onRefresh",[33,4680,1731],{"class":65},[33,4682,2830],{"class":73},[33,4684,320],{"class":65},[33,4686,4648],{"class":438},[33,4688,2008],{"class":73},[33,4690,4691],{"class":35,"line":175},[33,4692,59],{"emptyLinePlaceholder":58},[33,4694,4695,4697,4700,4702,4704,4707,4709,4711,4713,4715,4717,4719,4721,4723,4725],{"class":35,"line":190},[33,4696,66],{"class":65},[33,4698,4699],{"class":69}," AsyncResult",[33,4701,947],{"class":73},[33,4703,4572],{"class":69},[33,4705,4706],{"class":73},">({ ",[33,4708,4588],{"class":77},[33,4710,81],{"class":73},[33,4712,749],{"class":65},[33,4714,752],{"class":77},[33,4716,1894],{"class":73},[33,4718,1731],{"class":65},[33,4720,4567],{"class":69},[33,4722,947],{"class":73},[33,4724,4572],{"class":69},[33,4726,4727],{"class":73},">) {\n",[33,4729,4730,4733],{"class":35,"line":205},[33,4731,4732],{"class":65},"  switch",[33,4734,4735],{"class":73}," (status) {\n",[33,4737,4738,4741,4743],{"class":35,"line":215},[33,4739,4740],{"class":65},"    case",[33,4742,4593],{"class":132},[33,4744,4745],{"class":73},":\n",[33,4747,4748,4751,4753,4755,4757,4759,4762,4765,4767,4769],{"class":35,"line":221},[33,4749,4750],{"class":65},"      return",[33,4752,279],{"class":73},[33,4754,195],{"class":69},[33,4756,126],{"class":69},[33,4758,129],{"class":73},[33,4760,4761],{"class":132},"\"muted\"",[33,4763,4764],{"class":73},">Nothing loaded yet.",[33,4766,1914],{"class":65},[33,4768,195],{"class":73},[33,4770,136],{"class":65},[33,4772,4773,4775,4777],{"class":35,"line":227},[33,4774,4740],{"class":65},[33,4776,4608],{"class":132},[33,4778,4745],{"class":73},[33,4780,4781,4783,4785,4787],{"class":35,"line":232},[33,4782,4750],{"class":65},[33,4784,279],{"class":73},[33,4786,4450],{"class":69},[33,4788,3235],{"class":73},[33,4790,4791],{"class":35,"line":496},[33,4792,4793],{"class":73},"    case 'error': {\n",[33,4795,4796],{"class":35,"line":503},[33,4797,4798],{"class":73},"      \u002F\u002F TS narrows `rest` to { error, onRetry } here — accessing rest.data\n",[33,4800,4801],{"class":35,"line":509},[33,4802,4803],{"class":73},"      \u002F\u002F would be a compile error. Invalid combinations are impossible.\n",[33,4805,4806],{"class":35,"line":523},[33,4807,4808],{"class":73},"      const { error, onRetry } = rest\n",[33,4810,4811],{"class":35,"line":537},[33,4812,4813],{"class":73},"      return (\n",[33,4815,4816,4819,4822,4824,4827],{"class":35,"line":543},[33,4817,4818],{"class":65},"        \u003C",[33,4820,4821],{"class":73},"div className",[33,4823,129],{"class":65},[33,4825,4826],{"class":132},"\"error\"",[33,4828,136],{"class":65},[33,4830,4831,4834,4836,4839,4841,4843],{"class":35,"line":548},[33,4832,4833],{"class":73},"          \u003C",[33,4835,195],{"class":69},[33,4837,4838],{"class":73},">{error.message}",[33,4840,1914],{"class":65},[33,4842,195],{"class":73},[33,4844,136],{"class":65},[33,4846,4847,4849,4852,4854,4857,4860,4863,4865,4867],{"class":35,"line":1925},[33,4848,4833],{"class":65},[33,4850,4851],{"class":73},"button onClick",[33,4853,129],{"class":65},[33,4855,4856],{"class":73},"{onRetry}",[33,4858,4859],{"class":65},">",[33,4861,4862],{"class":73},"Retry",[33,4864,1914],{"class":65},[33,4866,282],{"class":73},[33,4868,136],{"class":65},[33,4870,4871,4874,4876],{"class":35,"line":1930},[33,4872,4873],{"class":65},"        \u003C\u002F",[33,4875,123],{"class":73},[33,4877,136],{"class":65},[33,4879,4880],{"class":35,"line":1939},[33,4881,4882],{"class":73},"      )\n",[33,4884,4885],{"class":35,"line":1948},[33,4886,4887],{"class":73},"    }\n",[33,4889,4890,4892,4894],{"class":35,"line":3589},[33,4891,4740],{"class":65},[33,4893,4663],{"class":132},[33,4895,4896],{"class":73},": {\n",[33,4898,4899],{"class":35,"line":3608},[33,4900,4901],{"class":73},"      const { data, onRefresh } = rest\n",[33,4903,4904,4906],{"class":35,"line":3614},[33,4905,4750],{"class":69},[33,4907,113],{"class":73},[33,4909,4910,4912,4914],{"class":35,"line":3620},[33,4911,4818],{"class":73},[33,4913,123],{"class":77},[33,4915,136],{"class":73},[33,4917,4918,4920,4922,4925,4928,4931,4934,4936,4938,4940,4942,4945,4947],{"class":35,"line":3629},[33,4919,4833],{"class":73},[33,4921,24],{"class":77},[33,4923,4924],{"class":73},">{",[33,4926,4927],{"class":77},"JSON",[33,4929,4930],{"class":73},".",[33,4932,4933],{"class":77},"stringify",[33,4935,577],{"class":73},[33,4937,4668],{"class":77},[33,4939,81],{"class":73},[33,4941,1011],{"class":77},[33,4943,4944],{"class":73},", 2)}\u003C\u002F",[33,4946,24],{"class":77},[33,4948,136],{"class":73},[33,4950,4951,4953,4955,4957,4959,4962,4964,4967,4969,4971],{"class":35,"line":3634},[33,4952,4833],{"class":73},[33,4954,282],{"class":77},[33,4956,961],{"class":77},[33,4958,129],{"class":65},[33,4960,4961],{"class":73},"{onRefresh}",[33,4963,4859],{"class":65},[33,4965,4966],{"class":73},"Refresh",[33,4968,1914],{"class":65},[33,4970,282],{"class":73},[33,4972,136],{"class":65},[33,4974,4975,4977,4979],{"class":35,"line":3639},[33,4976,4873],{"class":73},[33,4978,123],{"class":77},[33,4980,136],{"class":73},[33,4982,4983],{"class":35,"line":3644},[33,4984,4882],{"class":73},[33,4986,4987],{"class":35,"line":3658},[33,4988,4887],{"class":73},[33,4990,4991],{"class":35,"line":3680},[33,4992,4993],{"class":73},"  }\n",[33,4995,4996],{"class":35,"line":3685},[33,4997,224],{"class":73},[33,4999,5000],{"class":35,"line":3690},[33,5001,59],{"emptyLinePlaceholder":58},[33,5003,5004],{"class":35,"line":3708},[33,5005,5006],{"class":39},"\u002F\u002F USAGE — TS enforces the correct payload for each variant.\n",[33,5008,5009,5011,5014,5016,5019],{"class":35,"line":3725},[33,5010,947],{"class":65},[33,5012,5013],{"class":73},"AsyncResult status",[33,5015,129],{"class":65},[33,5017,5018],{"class":132},"\"idle\"",[33,5020,3235],{"class":65},[33,5022,5023,5025,5027,5029,5032],{"class":35,"line":3744},[33,5024,947],{"class":65},[33,5026,5013],{"class":73},[33,5028,129],{"class":65},[33,5030,5031],{"class":132},"\"loading\"",[33,5033,3235],{"class":65},[33,5035,5036,5038],{"class":35,"line":3766},[33,5037,947],{"class":65},[33,5039,5040],{"class":73},"AsyncResult\n",[33,5042,5043,5046,5048],{"class":35,"line":3771},[33,5044,5045],{"class":73},"  status",[33,5047,129],{"class":65},[33,5049,5050],{"class":132},"\"error\"\n",[33,5052,5053,5056,5058,5061,5064,5066,5069],{"class":35,"line":3776},[33,5054,5055],{"class":73},"  error",[33,5057,129],{"class":65},[33,5059,5060],{"class":73},"{new ",[33,5062,5063],{"class":69},"Error",[33,5065,577],{"class":73},[33,5067,5068],{"class":132},"'Network failed'",[33,5070,5071],{"class":73},")}\n",[33,5073,5074,5077,5079],{"class":35,"line":3782},[33,5075,5076],{"class":73},"  onRetry",[33,5078,129],{"class":65},[33,5080,5081],{"class":73},"{refetch}\n",[33,5083,5084],{"class":35,"line":3793},[33,5085,5086],{"class":65},"\u002F>\n",[33,5088,5089,5091,5093,5095,5098,5101,5103,5106,5108,5111],{"class":35,"line":3804},[33,5090,947],{"class":65},[33,5092,5013],{"class":73},[33,5094,129],{"class":65},[33,5096,5097],{"class":132},"\"success\"",[33,5099,5100],{"class":73}," data",[33,5102,129],{"class":65},[33,5104,5105],{"class":73},"{result} onRefresh",[33,5107,129],{"class":65},[33,5109,5110],{"class":73},"{refetch} ",[33,5112,5086],{"class":65},[33,5114,5115],{"class":35,"line":3815},[33,5116,59],{"emptyLinePlaceholder":58},[33,5118,5119,5122],{"class":35,"line":3826},[33,5120,5121],{"class":39},"\u002F\u002F WRONG (compile error): \u003CAsyncResult status=\"error\" \u002F>",[33,5123,5124],{"class":39},"      \u002F\u002F missing error, onRetry\n",[33,5126,5127,5130],{"class":35,"line":3831},[33,5128,5129],{"class":39},"\u002F\u002F WRONG (compile error): \u003CAsyncResult status=\"success\" data={x} \u002F>",[33,5131,5132],{"class":39},"  \u002F\u002F missing onRefresh\n",[14,5134,5136],{"id":5135},"tips-tricks","💡 Tips & Tricks",[19,5138,5140],{"filename":5139,"language":22},"tips.js",[24,5141,5143],{"className":26,"code":5142,"language":22,"meta":28,"style":28},"\u002F\u002F [Idiom] Destructure props in the signature, not inside the body. The parameter\n\u002F\u002F list IS the public API — it's the first thing a reader sees, and diffs stay\n\u002F\u002F minimal when you add or remove a prop.\n\n\u002F\u002F [Idiom] Forward unknown props with rest: `function Input({ label, ...rest })`.\n\u002F\u002F This builds flexible wrapper components without manually re-declaring every\n\u002F\u002F standard DOM attribute. Filter non-DOM props before spreading onto host elements\n\u002F\u002F to avoid React \"unknown prop\" warnings.\n\n\u002F\u002F [Performance] Inline objects\u002Farrays\u002Ffunctions as props create a NEW reference\n\u002F\u002F every render: \u003CWidget style={{ color: 'red' }} \u002F> defeats React.memo on Widget\n\u002F\u002F even though the value never changes — memo compares by reference. Lift stable\n\u002F\u002F objects outside the component or memoize with useMemo\u002FuseCallback (Ch 9, 20).\n\n\u002F\u002F [Debug] If a prop's default isn't applying, check whether the caller passes\n\u002F\u002F `null` instead of omitting it — default parameters only trigger on `undefined`.\n\u002F\u002F API responses often use `null` for \"empty,\" which silently bypasses defaults.\n\n\u002F\u002F [Idiom] Use `interface` for simple prop objects (lets consumers augment via\n\u002F\u002F declaration merging); use `type` when you need unions, intersections, or\n\u002F\u002F mapped utility types. Both are identical at runtime.\n\n\u002F\u002F [Debug] `children.map is not a function` means the component received a single\n\u002F\u002F child (an element or string), not an array. Use `React.Children.map` or\n\u002F\u002F `React.Children.toArray` for uniform handling regardless of child count.\n\n\u002F\u002F [Idiom] Prefer onMouseEnter\u002FonMouseLeave over onMouseOver\u002FonMouseOut for hover\n\u002F\u002F UI — Enter\u002FLeave doesn't bubble through children, avoiding flicker when the\n\u002F\u002F pointer crosses internal element boundaries within the hovered area.\n",[30,5144,5145,5150,5155,5160,5164,5169,5174,5179,5184,5188,5193,5198,5203,5208,5212,5217,5222,5227,5231,5236,5241,5246,5250,5255,5260,5265,5269,5274,5279],{"__ignoreMap":28},[33,5146,5147],{"class":35,"line":36},[33,5148,5149],{"class":39},"\u002F\u002F [Idiom] Destructure props in the signature, not inside the body. The parameter\n",[33,5151,5152],{"class":35,"line":43},[33,5153,5154],{"class":39},"\u002F\u002F list IS the public API — it's the first thing a reader sees, and diffs stay\n",[33,5156,5157],{"class":35,"line":49},[33,5158,5159],{"class":39},"\u002F\u002F minimal when you add or remove a prop.\n",[33,5161,5162],{"class":35,"line":55},[33,5163,59],{"emptyLinePlaceholder":58},[33,5165,5166],{"class":35,"line":62},[33,5167,5168],{"class":39},"\u002F\u002F [Idiom] Forward unknown props with rest: `function Input({ label, ...rest })`.\n",[33,5170,5171],{"class":35,"line":95},[33,5172,5173],{"class":39},"\u002F\u002F This builds flexible wrapper components without manually re-declaring every\n",[33,5175,5176],{"class":35,"line":101},[33,5177,5178],{"class":39},"\u002F\u002F standard DOM attribute. Filter non-DOM props before spreading onto host elements\n",[33,5180,5181],{"class":35,"line":107},[33,5182,5183],{"class":39},"\u002F\u002F to avoid React \"unknown prop\" warnings.\n",[33,5185,5186],{"class":35,"line":116},[33,5187,59],{"emptyLinePlaceholder":58},[33,5189,5190],{"class":35,"line":139},[33,5191,5192],{"class":39},"\u002F\u002F [Performance] Inline objects\u002Farrays\u002Ffunctions as props create a NEW reference\n",[33,5194,5195],{"class":35,"line":175},[33,5196,5197],{"class":39},"\u002F\u002F every render: \u003CWidget style={{ color: 'red' }} \u002F> defeats React.memo on Widget\n",[33,5199,5200],{"class":35,"line":190},[33,5201,5202],{"class":39},"\u002F\u002F even though the value never changes — memo compares by reference. Lift stable\n",[33,5204,5205],{"class":35,"line":205},[33,5206,5207],{"class":39},"\u002F\u002F objects outside the component or memoize with useMemo\u002FuseCallback (Ch 9, 20).\n",[33,5209,5210],{"class":35,"line":215},[33,5211,59],{"emptyLinePlaceholder":58},[33,5213,5214],{"class":35,"line":221},[33,5215,5216],{"class":39},"\u002F\u002F [Debug] If a prop's default isn't applying, check whether the caller passes\n",[33,5218,5219],{"class":35,"line":227},[33,5220,5221],{"class":39},"\u002F\u002F `null` instead of omitting it — default parameters only trigger on `undefined`.\n",[33,5223,5224],{"class":35,"line":232},[33,5225,5226],{"class":39},"\u002F\u002F API responses often use `null` for \"empty,\" which silently bypasses defaults.\n",[33,5228,5229],{"class":35,"line":496},[33,5230,59],{"emptyLinePlaceholder":58},[33,5232,5233],{"class":35,"line":503},[33,5234,5235],{"class":39},"\u002F\u002F [Idiom] Use `interface` for simple prop objects (lets consumers augment via\n",[33,5237,5238],{"class":35,"line":509},[33,5239,5240],{"class":39},"\u002F\u002F declaration merging); use `type` when you need unions, intersections, or\n",[33,5242,5243],{"class":35,"line":523},[33,5244,5245],{"class":39},"\u002F\u002F mapped utility types. Both are identical at runtime.\n",[33,5247,5248],{"class":35,"line":537},[33,5249,59],{"emptyLinePlaceholder":58},[33,5251,5252],{"class":35,"line":543},[33,5253,5254],{"class":39},"\u002F\u002F [Debug] `children.map is not a function` means the component received a single\n",[33,5256,5257],{"class":35,"line":548},[33,5258,5259],{"class":39},"\u002F\u002F child (an element or string), not an array. Use `React.Children.map` or\n",[33,5261,5262],{"class":35,"line":1925},[33,5263,5264],{"class":39},"\u002F\u002F `React.Children.toArray` for uniform handling regardless of child count.\n",[33,5266,5267],{"class":35,"line":1930},[33,5268,59],{"emptyLinePlaceholder":58},[33,5270,5271],{"class":35,"line":1939},[33,5272,5273],{"class":39},"\u002F\u002F [Idiom] Prefer onMouseEnter\u002FonMouseLeave over onMouseOver\u002FonMouseOut for hover\n",[33,5275,5276],{"class":35,"line":1948},[33,5277,5278],{"class":39},"\u002F\u002F UI — Enter\u002FLeave doesn't bubble through children, avoiding flicker when the\n",[33,5280,5281],{"class":35,"line":3589},[33,5282,5283],{"class":39},"\u002F\u002F pointer crosses internal element boundaries within the hovered area.\n",[14,5285,5287],{"id":5286},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[19,5289,5291],{"filename":5290,"language":22},"edge_cases.js",[24,5292,5294],{"className":26,"code":5293,"language":22,"meta":28,"style":28},"\u002F\u002F [Gotcha] Mutating an object\u002Farray prop mutates the PARENT's data — objects are\n\u002F\u002F references, not copies. props.items.push(x) corrupts the parent's array, and\n\u002F\u002F because the reference is unchanged, React may skip re-rendering → stale UI\n\u002F\u002F AND corrupted shared state. Always produce a new object\u002Farray.\n\n\u002F\u002F [Gotcha] `Component.defaultProps` on function components is deprecated (React\n\u002F\u002F 18.3+). It still runs today but logs a warning; a future major removes it.\n\u002F\u002F Use destructuring defaults ({ variant = 'primary' }) — identical runtime behavior.\n\n\u002F\u002F [Gotcha] Lowercase component names are silently treated as HTML tags. \u003CuserCard \u002F>\n\u002F\u002F does NOT error — JSX renders an unknown DOM element \u003Cusercard>, and your props\n\u002F\u002F become (warned, ignored) raw DOM attributes. Always PascalCase custom components.\n\n\u002F\u002F [Gotcha] Passing a new inline object\u002Farray\u002Ffunction as a prop creates a new\n\u002F\u002F reference every render, defeating React.memo even when values are unchanged.\n\u002F\u002F \u003CWidget style={{ color: 'red' }} \u002F> → new object each render → memo never bails out.\n\n\u002F\u002F [Gotcha] `children` with exactly one child is NOT an array — it's the child\n\u002F\u002F itself. children.map(...) throws \"is not a function\" in the single-child case.\n\u002F\u002F Use React.Children.map \u002F React.Children.toArray for count-agnostic handling.\n\n\u002F\u002F [Gotcha] Default parameters don't apply to `null` — only `undefined`. If an\n\u002F\u002F API returns null for \"empty,\" your default is silently skipped and the child\n\u002F\u002F receives null. Use `size ?? 40` (nullish coalescing) if null should fall back.\n\n\u002F\u002F [Gotcha] Boolean prop explosion creates invalid states. isLoading && isError\n\u002F\u002F is nonsensical but the API allows it. Use a discriminated union status prop\n\u002F\u002F to make invalid combinations structurally impossible, not just discouraged.\n\n\u002F\u002F [Gotcha] Returning multiple sibling elements without a Fragment is a syntax\n\u002F\u002F error or returns undefined. Wrap them in \u003C>\u003C\u002F> or \u003CReact.Fragment> — Fragments\n\u002F\u002F group without adding a wrapper \u003Cdiv> to the DOM, preserving CSS grid\u002Fflex layout.\n",[30,5295,5296,5301,5306,5311,5316,5320,5325,5330,5335,5339,5344,5349,5354,5358,5363,5368,5373,5377,5382,5387,5392,5396,5401,5406,5411,5415,5420,5425,5430,5434,5439,5444],{"__ignoreMap":28},[33,5297,5298],{"class":35,"line":36},[33,5299,5300],{"class":39},"\u002F\u002F [Gotcha] Mutating an object\u002Farray prop mutates the PARENT's data — objects are\n",[33,5302,5303],{"class":35,"line":43},[33,5304,5305],{"class":39},"\u002F\u002F references, not copies. props.items.push(x) corrupts the parent's array, and\n",[33,5307,5308],{"class":35,"line":49},[33,5309,5310],{"class":39},"\u002F\u002F because the reference is unchanged, React may skip re-rendering → stale UI\n",[33,5312,5313],{"class":35,"line":55},[33,5314,5315],{"class":39},"\u002F\u002F AND corrupted shared state. Always produce a new object\u002Farray.\n",[33,5317,5318],{"class":35,"line":62},[33,5319,59],{"emptyLinePlaceholder":58},[33,5321,5322],{"class":35,"line":95},[33,5323,5324],{"class":39},"\u002F\u002F [Gotcha] `Component.defaultProps` on function components is deprecated (React\n",[33,5326,5327],{"class":35,"line":101},[33,5328,5329],{"class":39},"\u002F\u002F 18.3+). It still runs today but logs a warning; a future major removes it.\n",[33,5331,5332],{"class":35,"line":107},[33,5333,5334],{"class":39},"\u002F\u002F Use destructuring defaults ({ variant = 'primary' }) — identical runtime behavior.\n",[33,5336,5337],{"class":35,"line":116},[33,5338,59],{"emptyLinePlaceholder":58},[33,5340,5341],{"class":35,"line":139},[33,5342,5343],{"class":39},"\u002F\u002F [Gotcha] Lowercase component names are silently treated as HTML tags. \u003CuserCard \u002F>\n",[33,5345,5346],{"class":35,"line":175},[33,5347,5348],{"class":39},"\u002F\u002F does NOT error — JSX renders an unknown DOM element \u003Cusercard>, and your props\n",[33,5350,5351],{"class":35,"line":190},[33,5352,5353],{"class":39},"\u002F\u002F become (warned, ignored) raw DOM attributes. Always PascalCase custom components.\n",[33,5355,5356],{"class":35,"line":205},[33,5357,59],{"emptyLinePlaceholder":58},[33,5359,5360],{"class":35,"line":215},[33,5361,5362],{"class":39},"\u002F\u002F [Gotcha] Passing a new inline object\u002Farray\u002Ffunction as a prop creates a new\n",[33,5364,5365],{"class":35,"line":221},[33,5366,5367],{"class":39},"\u002F\u002F reference every render, defeating React.memo even when values are unchanged.\n",[33,5369,5370],{"class":35,"line":227},[33,5371,5372],{"class":39},"\u002F\u002F \u003CWidget style={{ color: 'red' }} \u002F> → new object each render → memo never bails out.\n",[33,5374,5375],{"class":35,"line":232},[33,5376,59],{"emptyLinePlaceholder":58},[33,5378,5379],{"class":35,"line":496},[33,5380,5381],{"class":39},"\u002F\u002F [Gotcha] `children` with exactly one child is NOT an array — it's the child\n",[33,5383,5384],{"class":35,"line":503},[33,5385,5386],{"class":39},"\u002F\u002F itself. children.map(...) throws \"is not a function\" in the single-child case.\n",[33,5388,5389],{"class":35,"line":509},[33,5390,5391],{"class":39},"\u002F\u002F Use React.Children.map \u002F React.Children.toArray for count-agnostic handling.\n",[33,5393,5394],{"class":35,"line":523},[33,5395,59],{"emptyLinePlaceholder":58},[33,5397,5398],{"class":35,"line":537},[33,5399,5400],{"class":39},"\u002F\u002F [Gotcha] Default parameters don't apply to `null` — only `undefined`. If an\n",[33,5402,5403],{"class":35,"line":543},[33,5404,5405],{"class":39},"\u002F\u002F API returns null for \"empty,\" your default is silently skipped and the child\n",[33,5407,5408],{"class":35,"line":548},[33,5409,5410],{"class":39},"\u002F\u002F receives null. Use `size ?? 40` (nullish coalescing) if null should fall back.\n",[33,5412,5413],{"class":35,"line":1925},[33,5414,59],{"emptyLinePlaceholder":58},[33,5416,5417],{"class":35,"line":1930},[33,5418,5419],{"class":39},"\u002F\u002F [Gotcha] Boolean prop explosion creates invalid states. isLoading && isError\n",[33,5421,5422],{"class":35,"line":1939},[33,5423,5424],{"class":39},"\u002F\u002F is nonsensical but the API allows it. Use a discriminated union status prop\n",[33,5426,5427],{"class":35,"line":1948},[33,5428,5429],{"class":39},"\u002F\u002F to make invalid combinations structurally impossible, not just discouraged.\n",[33,5431,5432],{"class":35,"line":3589},[33,5433,59],{"emptyLinePlaceholder":58},[33,5435,5436],{"class":35,"line":3608},[33,5437,5438],{"class":39},"\u002F\u002F [Gotcha] Returning multiple sibling elements without a Fragment is a syntax\n",[33,5440,5441],{"class":35,"line":3614},[33,5442,5443],{"class":39},"\u002F\u002F error or returns undefined. Wrap them in \u003C>\u003C\u002F> or \u003CReact.Fragment> — Fragments\n",[33,5445,5446],{"class":35,"line":3620},[33,5447,5448],{"class":39},"\u002F\u002F group without adding a wrapper \u003Cdiv> to the DOM, preserving CSS grid\u002Fflex layout.\n",[14,5450,5452],{"id":5451},"spot-the-bug","🧠 Spot the Bug",[195,5454,5455],{},"A settings panel mutates a preference checkbox, but the change \"leaks\" into another user's cached card elsewhere on the page.",[19,5457,5459],{"filename":5458,"language":22},"spot_the_bug.js",[24,5460,5462],{"className":26,"code":5461,"language":22,"meta":28,"style":28},"function NotificationSettings({ preferences }) {\n  function toggleEmail() {\n    preferences.email = !preferences.email  \u002F\u002F mutate in place\n    forceRerender()\n  }\n\n  return (\n    \u003Clabel>\n      \u003Cinput type=\"checkbox\" checked={preferences.email} onChange={toggleEmail} \u002F>\n      Email notifications\n    \u003C\u002Flabel>\n  )\n}\n",[30,5463,5464,5478,5488,5503,5511,5515,5519,5525,5533,5562,5567,5575,5579],{"__ignoreMap":28},[33,5465,5466,5468,5471,5473,5476],{"class":35,"line":36},[33,5467,66],{"class":65},[33,5469,5470],{"class":69}," NotificationSettings",[33,5472,74],{"class":73},[33,5474,5475],{"class":77},"preferences",[33,5477,92],{"class":73},[33,5479,5480,5483,5486],{"class":35,"line":43},[33,5481,5482],{"class":65},"  function",[33,5484,5485],{"class":69}," toggleEmail",[33,5487,493],{"class":73},[33,5489,5490,5493,5495,5497,5500],{"class":35,"line":49},[33,5491,5492],{"class":73},"    preferences.email ",[33,5494,129],{"class":65},[33,5496,2845],{"class":65},[33,5498,5499],{"class":73},"preferences.email  ",[33,5501,5502],{"class":39},"\u002F\u002F mutate in place\n",[33,5504,5505,5508],{"class":35,"line":55},[33,5506,5507],{"class":69},"    forceRerender",[33,5509,5510],{"class":73},"()\n",[33,5512,5513],{"class":35,"line":62},[33,5514,4993],{"class":73},[33,5516,5517],{"class":35,"line":95},[33,5518,59],{"emptyLinePlaceholder":58},[33,5520,5521,5523],{"class":35,"line":101},[33,5522,110],{"class":65},[33,5524,113],{"class":73},[33,5526,5527,5529,5531],{"class":35,"line":107},[33,5528,119],{"class":73},[33,5530,270],{"class":122},[33,5532,136],{"class":73},[33,5534,5535,5537,5539,5542,5544,5547,5550,5552,5555,5557,5559],{"class":35,"line":116},[33,5536,142],{"class":73},[33,5538,780],{"class":122},[33,5540,5541],{"class":69}," type",[33,5543,129],{"class":65},[33,5545,5546],{"class":132},"\"checkbox\"",[33,5548,5549],{"class":69}," checked",[33,5551,129],{"class":65},[33,5553,5554],{"class":73},"{preferences.email} ",[33,5556,3036],{"class":69},[33,5558,129],{"class":65},[33,5560,5561],{"class":73},"{toggleEmail} \u002F>\n",[33,5563,5564],{"class":35,"line":139},[33,5565,5566],{"class":73},"      Email notifications\n",[33,5568,5569,5571,5573],{"class":35,"line":175},[33,5570,208],{"class":73},[33,5572,270],{"class":122},[33,5574,136],{"class":73},[33,5576,5577],{"class":35,"line":190},[33,5578,218],{"class":73},[33,5580,5581],{"class":35,"line":205},[33,5582,224],{"class":73},[5584,5585,5586,5590,5604,5611,5722],"details",{},[5587,5588,5589],"summary",{},"Answer",[195,5591,5592,5594,5595,5598,5599,5603],{},[30,5593,5475],{}," is an object reference shared with a cache or context. Mutating ",[30,5596,5597],{},"preferences.email"," in place changes the ",[5600,5601,5602],"em",{},"same object"," other components hold — they see the change without ever receiving a prop update. Because the reference is unchanged, React's reconciliation may skip re-rendering the owner, so the mutation is invisible to the data flow but visible as corrupted UI in siblings.",[195,5605,5606,5610],{},[5607,5608,5609],"strong",{},"Fix",": never mutate a prop. Derive a new object and pass it up via a callback so the state owner updates immutably:",[24,5612,5614],{"className":26,"code":5613,"language":22,"meta":28,"style":28},"function NotificationSettings({ preferences, onUpdate }) {\n  return (\n    \u003Clabel>\n      \u003Cinput\n        type=\"checkbox\"\n        checked={preferences.email}\n        onChange={() => onUpdate({ ...preferences, email: !preferences.email })}\n      \u002F>\n      Email notifications\n    \u003C\u002Flabel>\n  )\n}\n",[30,5615,5616,5632,5638,5646,5652,5662,5672,5697,5702,5706,5714,5718],{"__ignoreMap":28},[33,5617,5618,5620,5622,5624,5626,5628,5630],{"class":35,"line":36},[33,5619,66],{"class":65},[33,5621,5470],{"class":69},[33,5623,74],{"class":73},[33,5625,5475],{"class":77},[33,5627,81],{"class":73},[33,5629,1432],{"class":77},[33,5631,92],{"class":73},[33,5633,5634,5636],{"class":35,"line":43},[33,5635,110],{"class":65},[33,5637,113],{"class":73},[33,5639,5640,5642,5644],{"class":35,"line":49},[33,5641,119],{"class":73},[33,5643,270],{"class":122},[33,5645,136],{"class":73},[33,5647,5648,5650],{"class":35,"line":55},[33,5649,142],{"class":73},[33,5651,1447],{"class":122},[33,5653,5654,5657,5659],{"class":35,"line":62},[33,5655,5656],{"class":69},"        type",[33,5658,129],{"class":65},[33,5660,5661],{"class":132},"\"checkbox\"\n",[33,5663,5664,5667,5669],{"class":35,"line":95},[33,5665,5666],{"class":69},"        checked",[33,5668,129],{"class":65},[33,5670,5671],{"class":73},"{preferences.email}\n",[33,5673,5674,5677,5679,5681,5683,5685,5687,5689,5692,5694],{"class":35,"line":101},[33,5675,5676],{"class":69},"        onChange",[33,5678,129],{"class":65},[33,5680,3597],{"class":73},[33,5682,320],{"class":65},[33,5684,1478],{"class":69},[33,5686,74],{"class":73},[33,5688,749],{"class":65},[33,5690,5691],{"class":73},"preferences, email: ",[33,5693,430],{"class":65},[33,5695,5696],{"class":73},"preferences.email })}\n",[33,5698,5699],{"class":35,"line":107},[33,5700,5701],{"class":73},"      \u002F>\n",[33,5703,5704],{"class":35,"line":116},[33,5705,5566],{"class":73},[33,5707,5708,5710,5712],{"class":35,"line":139},[33,5709,208],{"class":73},[33,5711,270],{"class":122},[33,5713,136],{"class":73},[33,5715,5716],{"class":35,"line":175},[33,5717,218],{"class":73},[33,5719,5720],{"class":35,"line":190},[33,5721,224],{"class":73},[195,5723,5724,5727],{},[5607,5725,5726],{},"The lesson",": props are read-only by contract. Objects are references — in-place mutation corrupts the parent and any sibling sharing that reference, while React's referential-equality bailout may hide the change from the render cycle entirely.",[14,5729,5731],{"id":5730},"key-takeaways","Key Takeaways",[19,5733,5735],{"filename":5734,"language":22},"key_takeaways.js",[24,5736,5738],{"className":26,"code":5737,"language":22,"meta":28,"style":28},"\u002F\u002F 1. Function components are pure functions: props in, JSX (or null) out.\n\u002F\u002F    PascalCase is mandatory — lowercase tags are treated as host DOM elements.\n\u002F\u002F    Valid returns: single element, null, keyed array, string\u002Fnumber, Fragment, Portal.\n\n\u002F\u002F 2. Props are READ-ONLY — never mutate. React reconciles by referential equality:\n\u002F\u002F    mutating an object prop leaves the reference unchanged → React skips re-render\n\u002F\u002F    → stale UI AND corrupted parent\u002Fsibling state (objects are references, not copies).\n\n\u002F\u002F 3. Destructure in the signature — the parameter list IS the public API.\n\u002F\u002F    Defaults via destructuring ({ variant = 'primary' }) replaced defaultProps\n\u002F\u002F    (deprecated React 18.3+). Defaults apply ONLY to undefined, never to null.\n\n\u002F\u002F 4. `children` is the special composition prop. It is NOT always an array —\n\u002F\u002F    a single child arrives as the child itself. Use React.Children.map\u002FtoArray\n\u002F\u002F    for count-agnostic handling.\n\n\u002F\u002F 5. Children patterns: render props (function decides JSX), function-as-child\n\u002F\u002F    (children IS the render prop), cloneElement (inject props into received\n\u002F\u002F    elements). Modern React often replaces render props with custom hooks.\n\n\u002F\u002F 6. Compound components share implicit state via Context — declarative assembly\n\u002F\u002F    without prop drilling. Attach sub-components as static properties (Tabs.Tab).\n\n\u002F\u002F 7. Anti-patterns: prop drilling (fix: Context Ch 7 \u002F composition Ch 15),\n\u002F\u002F    prop mutation (fix: immutable update + callback), boolean prop explosion\n\u002F\u002F    (fix: discriminated union — make invalid states unrepresentable).\n\n\u002F\u002F 8. TypeScript interfaces give compile-time prop safety; PropTypes is legacy-\n\u002F\u002F    literacy (runtime warnings only, zero editor support). Prefer `interface`\n\u002F\u002F    for plain object props (augmentable), `type` for unions\u002Fintersections.\n\n\u002F\u002F 9. Inline object\u002Farray\u002Ffunction props create new references every render,\n\u002F\u002F    defeating React.memo. Lift stable values or memoize (Ch 9, 20).\n",[30,5739,5740,5745,5750,5755,5759,5764,5769,5774,5778,5783,5788,5793,5797,5802,5807,5812,5816,5821,5826,5831,5835,5840,5845,5849,5854,5859,5864,5868,5873,5878,5883,5887,5892],{"__ignoreMap":28},[33,5741,5742],{"class":35,"line":36},[33,5743,5744],{"class":39},"\u002F\u002F 1. Function components are pure functions: props in, JSX (or null) out.\n",[33,5746,5747],{"class":35,"line":43},[33,5748,5749],{"class":39},"\u002F\u002F    PascalCase is mandatory — lowercase tags are treated as host DOM elements.\n",[33,5751,5752],{"class":35,"line":49},[33,5753,5754],{"class":39},"\u002F\u002F    Valid returns: single element, null, keyed array, string\u002Fnumber, Fragment, Portal.\n",[33,5756,5757],{"class":35,"line":55},[33,5758,59],{"emptyLinePlaceholder":58},[33,5760,5761],{"class":35,"line":62},[33,5762,5763],{"class":39},"\u002F\u002F 2. Props are READ-ONLY — never mutate. React reconciles by referential equality:\n",[33,5765,5766],{"class":35,"line":95},[33,5767,5768],{"class":39},"\u002F\u002F    mutating an object prop leaves the reference unchanged → React skips re-render\n",[33,5770,5771],{"class":35,"line":101},[33,5772,5773],{"class":39},"\u002F\u002F    → stale UI AND corrupted parent\u002Fsibling state (objects are references, not copies).\n",[33,5775,5776],{"class":35,"line":107},[33,5777,59],{"emptyLinePlaceholder":58},[33,5779,5780],{"class":35,"line":116},[33,5781,5782],{"class":39},"\u002F\u002F 3. Destructure in the signature — the parameter list IS the public API.\n",[33,5784,5785],{"class":35,"line":139},[33,5786,5787],{"class":39},"\u002F\u002F    Defaults via destructuring ({ variant = 'primary' }) replaced defaultProps\n",[33,5789,5790],{"class":35,"line":175},[33,5791,5792],{"class":39},"\u002F\u002F    (deprecated React 18.3+). Defaults apply ONLY to undefined, never to null.\n",[33,5794,5795],{"class":35,"line":190},[33,5796,59],{"emptyLinePlaceholder":58},[33,5798,5799],{"class":35,"line":205},[33,5800,5801],{"class":39},"\u002F\u002F 4. `children` is the special composition prop. It is NOT always an array —\n",[33,5803,5804],{"class":35,"line":215},[33,5805,5806],{"class":39},"\u002F\u002F    a single child arrives as the child itself. Use React.Children.map\u002FtoArray\n",[33,5808,5809],{"class":35,"line":221},[33,5810,5811],{"class":39},"\u002F\u002F    for count-agnostic handling.\n",[33,5813,5814],{"class":35,"line":227},[33,5815,59],{"emptyLinePlaceholder":58},[33,5817,5818],{"class":35,"line":232},[33,5819,5820],{"class":39},"\u002F\u002F 5. Children patterns: render props (function decides JSX), function-as-child\n",[33,5822,5823],{"class":35,"line":496},[33,5824,5825],{"class":39},"\u002F\u002F    (children IS the render prop), cloneElement (inject props into received\n",[33,5827,5828],{"class":35,"line":503},[33,5829,5830],{"class":39},"\u002F\u002F    elements). Modern React often replaces render props with custom hooks.\n",[33,5832,5833],{"class":35,"line":509},[33,5834,59],{"emptyLinePlaceholder":58},[33,5836,5837],{"class":35,"line":523},[33,5838,5839],{"class":39},"\u002F\u002F 6. Compound components share implicit state via Context — declarative assembly\n",[33,5841,5842],{"class":35,"line":537},[33,5843,5844],{"class":39},"\u002F\u002F    without prop drilling. Attach sub-components as static properties (Tabs.Tab).\n",[33,5846,5847],{"class":35,"line":543},[33,5848,59],{"emptyLinePlaceholder":58},[33,5850,5851],{"class":35,"line":548},[33,5852,5853],{"class":39},"\u002F\u002F 7. Anti-patterns: prop drilling (fix: Context Ch 7 \u002F composition Ch 15),\n",[33,5855,5856],{"class":35,"line":1925},[33,5857,5858],{"class":39},"\u002F\u002F    prop mutation (fix: immutable update + callback), boolean prop explosion\n",[33,5860,5861],{"class":35,"line":1930},[33,5862,5863],{"class":39},"\u002F\u002F    (fix: discriminated union — make invalid states unrepresentable).\n",[33,5865,5866],{"class":35,"line":1939},[33,5867,59],{"emptyLinePlaceholder":58},[33,5869,5870],{"class":35,"line":1948},[33,5871,5872],{"class":39},"\u002F\u002F 8. TypeScript interfaces give compile-time prop safety; PropTypes is legacy-\n",[33,5874,5875],{"class":35,"line":3589},[33,5876,5877],{"class":39},"\u002F\u002F    literacy (runtime warnings only, zero editor support). Prefer `interface`\n",[33,5879,5880],{"class":35,"line":3608},[33,5881,5882],{"class":39},"\u002F\u002F    for plain object props (augmentable), `type` for unions\u002Fintersections.\n",[33,5884,5885],{"class":35,"line":3614},[33,5886,59],{"emptyLinePlaceholder":58},[33,5888,5889],{"class":35,"line":3620},[33,5890,5891],{"class":39},"\u002F\u002F 9. Inline object\u002Farray\u002Ffunction props create new references every render,\n",[33,5893,5894],{"class":35,"line":3629},[33,5895,5896],{"class":39},"\u002F\u002F    defeating React.memo. Lift stable values or memoize (Ch 9, 20).\n",[5898,5899,5900],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}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 .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}",{"title":28,"searchDepth":43,"depth":43,"links":5902},[5903,5907,5913,5916,5922,5927,5934,5935,5940,5941,5942,5943,5944],{"id":16,"depth":43,"text":17,"children":5904},[5905,5906],{"id":244,"depth":49,"text":245},{"id":357,"depth":49,"text":358},{"id":553,"depth":43,"text":554,"children":5908},[5909,5911],{"id":807,"depth":49,"text":5910},"Destructuring Defaults — The Modern Replacement for defaultProps",{"id":1003,"depth":49,"text":5912},"Gotcha: Defaults Apply Only to undefined, Never to null",{"id":1205,"depth":43,"text":1206,"children":5914},[5915],{"id":1349,"depth":49,"text":1350},{"id":1504,"depth":43,"text":1505,"children":5917},[5918,5919,5920],{"id":1508,"depth":49,"text":1509},{"id":1683,"depth":49,"text":1684},{"id":1954,"depth":49,"text":5921},"type Alias vs interface for Props",{"id":2086,"depth":43,"text":5923,"children":5924},"The children Prop",[5925],{"id":2268,"depth":49,"text":5926},"children Is Not Always an Array",{"id":2518,"depth":43,"text":2519,"children":5928},[5929,5930,5932],{"id":2522,"depth":49,"text":2523},{"id":2751,"depth":49,"text":5931},"Function-as-Child (FaCC) — children Itself Is the Render Prop",{"id":2968,"depth":49,"text":5933},"cloneElement — Inject Props Into an Existing Element",{"id":3290,"depth":43,"text":3291},{"id":3996,"depth":43,"text":3997,"children":5936},[5937,5938,5939],{"id":4000,"depth":49,"text":4001},{"id":4257,"depth":49,"text":4258},{"id":4375,"depth":49,"text":4376},{"id":4522,"depth":43,"text":4523},{"id":5135,"depth":43,"text":5136},{"id":5286,"depth":43,"text":5287},{"id":5451,"depth":43,"text":5452},{"id":5730,"depth":43,"text":5731},"Function component anatomy, props as read-only referential-equality contract, PropTypes vs TypeScript, children render-prop and cloneElement patterns, compound components, discriminated-union props, anti-patterns. Code-first reference for mid-to-senior React engineers.","md",{},"\u002Freact\u002F03-components-and-props",{"title":5,"description":5945},"react\u002F03-components-and-props","ZmjNWpqG2c-IVDCB8kWNnpqGSxxytTmGcJ6SE_oEQnM",1789924651988]