[{"data":1,"prerenderedAt":2199},["ShallowReactive",2],{"page-\u002Freact\u002F07-usecontext-and-prop-drilling":3},{"id":4,"title":5,"body":6,"description":2192,"extension":2193,"meta":2194,"navigation":282,"path":2195,"seo":2196,"stem":2197,"__hash__":2198},"content\u002Freact\u002F07-usecontext-and-prop-drilling.md","07 — useContext & Prop Drilling",{"type":7,"value":8,"toc":2181},"minimark",[9,19,24,251,255,529,533,852,856,1375,1379,1567,1571,1670,1674,1813,1817,1821,1990,2084,2088,2177],[10,11,13,14,18],"h1",{"id":12},"_07-usecontext-prop-drilling","07 — ",[15,16,17],"code",{},"useContext"," & Prop Drilling",[20,21,23],"h2",{"id":22},"the-problem-prop-drilling","The Problem: Prop Drilling",[25,26,29],"code-wrapper",{"filename":27,"language":28},"prop_drilling.js","javascript",[30,31,35],"pre",{"className":32,"code":33,"language":28,"meta":34,"style":34},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F ANTI-PATTERN: passing props through components that don't use them\nfunction App() {\n  const [user, setUser] = useState(null)\n  return \u003CLayout user={user} setUser={setUser} \u002F>  \u002F\u002F Layout doesn't use user\n}\nfunction Layout({ user, setUser }) {\n  return \u003CSidebar user={user} setUser={setUser} \u002F>  \u002F\u002F Sidebar doesn't use user\n}\nfunction Sidebar({ user, setUser }) {\n  return \u003CUserMenu user={user} setUser={setUser} \u002F>  \u002F\u002F UserMenu is the actual consumer\n}\n\u002F\u002F 3 levels of drilling for a value only UserMenu needs.\n\u002F\u002F Adding a new prop to user → update every intermediate component's interface.\n\u002F\u002F Refactoring any intermediate component → risk breaking the prop chain.\n","",[15,36,37,46,61,98,128,134,155,180,185,203,228,233,239,245],{"__ignoreMap":34},[38,39,42],"span",{"class":40,"line":41},"line",1,[38,43,45],{"class":44},"sdCPZ","\u002F\u002F ANTI-PATTERN: passing props through components that don't use them\n",[38,47,49,53,57],{"class":40,"line":48},2,[38,50,52],{"class":51},"svdQ7","function",[38,54,56],{"class":55},"sIsaT"," App",[38,58,60],{"class":59},"ssxIu","() {\n",[38,62,64,67,70,74,77,80,83,86,89,92,95],{"class":40,"line":63},3,[38,65,66],{"class":51},"  const",[38,68,69],{"class":59}," [",[38,71,73],{"class":72},"snvgF","user",[38,75,76],{"class":59},", ",[38,78,79],{"class":72},"setUser",[38,81,82],{"class":59},"] ",[38,84,85],{"class":51},"=",[38,87,88],{"class":55}," useState",[38,90,91],{"class":59},"(",[38,93,94],{"class":72},"null",[38,96,97],{"class":59},")\n",[38,99,101,104,107,110,113,115,118,120,122,125],{"class":40,"line":100},4,[38,102,103],{"class":51},"  return",[38,105,106],{"class":59}," \u003C",[38,108,109],{"class":72},"Layout",[38,111,112],{"class":55}," user",[38,114,85],{"class":51},[38,116,117],{"class":59},"{user} ",[38,119,79],{"class":55},[38,121,85],{"class":51},[38,123,124],{"class":59},"{setUser} \u002F>  ",[38,126,127],{"class":44},"\u002F\u002F Layout doesn't use user\n",[38,129,131],{"class":40,"line":130},5,[38,132,133],{"class":59},"}\n",[38,135,137,139,142,145,148,150,152],{"class":40,"line":136},6,[38,138,52],{"class":51},[38,140,141],{"class":55}," Layout",[38,143,144],{"class":59},"({ ",[38,146,73],{"class":147},"sCrzJ",[38,149,76],{"class":59},[38,151,79],{"class":147},[38,153,154],{"class":59}," }) {\n",[38,156,158,160,162,165,167,169,171,173,175,177],{"class":40,"line":157},7,[38,159,103],{"class":51},[38,161,106],{"class":59},[38,163,164],{"class":72},"Sidebar",[38,166,112],{"class":55},[38,168,85],{"class":51},[38,170,117],{"class":59},[38,172,79],{"class":55},[38,174,85],{"class":51},[38,176,124],{"class":59},[38,178,179],{"class":44},"\u002F\u002F Sidebar doesn't use user\n",[38,181,183],{"class":40,"line":182},8,[38,184,133],{"class":59},[38,186,188,190,193,195,197,199,201],{"class":40,"line":187},9,[38,189,52],{"class":51},[38,191,192],{"class":55}," Sidebar",[38,194,144],{"class":59},[38,196,73],{"class":147},[38,198,76],{"class":59},[38,200,79],{"class":147},[38,202,154],{"class":59},[38,204,206,208,210,213,215,217,219,221,223,225],{"class":40,"line":205},10,[38,207,103],{"class":51},[38,209,106],{"class":59},[38,211,212],{"class":72},"UserMenu",[38,214,112],{"class":55},[38,216,85],{"class":51},[38,218,117],{"class":59},[38,220,79],{"class":55},[38,222,85],{"class":51},[38,224,124],{"class":59},[38,226,227],{"class":44},"\u002F\u002F UserMenu is the actual consumer\n",[38,229,231],{"class":40,"line":230},11,[38,232,133],{"class":59},[38,234,236],{"class":40,"line":235},12,[38,237,238],{"class":44},"\u002F\u002F 3 levels of drilling for a value only UserMenu needs.\n",[38,240,242],{"class":40,"line":241},13,[38,243,244],{"class":44},"\u002F\u002F Adding a new prop to user → update every intermediate component's interface.\n",[38,246,248],{"class":40,"line":247},14,[38,249,250],{"class":44},"\u002F\u002F Refactoring any intermediate component → risk breaking the prop chain.\n",[20,252,254],{"id":253},"createcontext-usecontext","createContext + useContext",[25,256,258],{"filename":257,"language":28},"context_basics.js",[30,259,261],{"className":32,"code":260,"language":28,"meta":34,"style":34},"import { createContext, useContext, useState } from 'react'\n\n\u002F\u002F 1. Create a context with a default value (used only when NO provider is found)\nconst AuthContext = createContext(null)  \u002F\u002F null default = \"no auth context\"\n\n\u002F\u002F 2. Provide a value at the top of the tree\nfunction App() {\n  const [user, setUser] = useState(null)\n  return (\n    \u003CAuthContext.Provider value={{ user, setUser }}>\n      \u003CLayout \u002F>\n    \u003C\u002FAuthContext.Provider>\n  )\n}\n\n\u002F\u002F 3. Consume in any descendant — no drilling through intermediate components\nfunction UserMenu() {\n  const { user, setUser } = useContext(AuthContext)  \u002F\u002F directly, no props\n  if (!user) return \u003CLoginButton onClick={() => setUser(loginUser())} \u002F>\n  return \u003Cdiv>{user.name}\u003C\u002Fdiv>\n}\n\u002F\u002F Layout and Sidebar no longer need to know about user at all.\n",[15,262,263,278,284,289,313,317,322,330,354,361,377,387,397,402,406,411,417,427,455,500,518,523],{"__ignoreMap":34},[38,264,265,268,271,274],{"class":40,"line":41},[38,266,267],{"class":51},"import",[38,269,270],{"class":59}," { createContext, useContext, useState } ",[38,272,273],{"class":51},"from",[38,275,277],{"class":276},"sJ6F3"," 'react'\n",[38,279,280],{"class":40,"line":48},[38,281,283],{"emptyLinePlaceholder":282},true,"\n",[38,285,286],{"class":40,"line":63},[38,287,288],{"class":44},"\u002F\u002F 1. Create a context with a default value (used only when NO provider is found)\n",[38,290,291,294,297,300,303,305,307,310],{"class":40,"line":100},[38,292,293],{"class":51},"const",[38,295,296],{"class":72}," AuthContext",[38,298,299],{"class":51}," =",[38,301,302],{"class":55}," createContext",[38,304,91],{"class":59},[38,306,94],{"class":72},[38,308,309],{"class":59},")  ",[38,311,312],{"class":44},"\u002F\u002F null default = \"no auth context\"\n",[38,314,315],{"class":40,"line":130},[38,316,283],{"emptyLinePlaceholder":282},[38,318,319],{"class":40,"line":136},[38,320,321],{"class":44},"\u002F\u002F 2. Provide a value at the top of the tree\n",[38,323,324,326,328],{"class":40,"line":157},[38,325,52],{"class":51},[38,327,56],{"class":55},[38,329,60],{"class":59},[38,331,332,334,336,338,340,342,344,346,348,350,352],{"class":40,"line":182},[38,333,66],{"class":51},[38,335,69],{"class":59},[38,337,73],{"class":72},[38,339,76],{"class":59},[38,341,79],{"class":72},[38,343,82],{"class":59},[38,345,85],{"class":51},[38,347,88],{"class":55},[38,349,91],{"class":59},[38,351,94],{"class":72},[38,353,97],{"class":59},[38,355,356,358],{"class":40,"line":187},[38,357,103],{"class":51},[38,359,360],{"class":59}," (\n",[38,362,363,366,369,372,374],{"class":40,"line":205},[38,364,365],{"class":59},"    \u003C",[38,367,368],{"class":72},"AuthContext.Provider",[38,370,371],{"class":55}," value",[38,373,85],{"class":51},[38,375,376],{"class":59},"{{ user, setUser }}>\n",[38,378,379,382,384],{"class":40,"line":230},[38,380,381],{"class":59},"      \u003C",[38,383,109],{"class":72},[38,385,386],{"class":59}," \u002F>\n",[38,388,389,392,394],{"class":40,"line":235},[38,390,391],{"class":59},"    \u003C\u002F",[38,393,368],{"class":72},[38,395,396],{"class":59},">\n",[38,398,399],{"class":40,"line":241},[38,400,401],{"class":59},"  )\n",[38,403,404],{"class":40,"line":247},[38,405,133],{"class":59},[38,407,409],{"class":40,"line":408},15,[38,410,283],{"emptyLinePlaceholder":282},[38,412,414],{"class":40,"line":413},16,[38,415,416],{"class":44},"\u002F\u002F 3. Consume in any descendant — no drilling through intermediate components\n",[38,418,420,422,425],{"class":40,"line":419},17,[38,421,52],{"class":51},[38,423,424],{"class":55}," UserMenu",[38,426,60],{"class":59},[38,428,430,432,435,437,439,441,444,446,449,452],{"class":40,"line":429},18,[38,431,66],{"class":51},[38,433,434],{"class":59}," { ",[38,436,73],{"class":72},[38,438,76],{"class":59},[38,440,79],{"class":72},[38,442,443],{"class":59}," } ",[38,445,85],{"class":51},[38,447,448],{"class":55}," useContext",[38,450,451],{"class":59},"(AuthContext)  ",[38,453,454],{"class":44},"\u002F\u002F directly, no props\n",[38,456,458,461,464,467,470,473,475,478,481,483,486,489,492,494,497],{"class":40,"line":457},19,[38,459,460],{"class":51},"  if",[38,462,463],{"class":59}," (",[38,465,466],{"class":51},"!",[38,468,469],{"class":59},"user) ",[38,471,472],{"class":51},"return",[38,474,106],{"class":59},[38,476,477],{"class":72},"LoginButton",[38,479,480],{"class":55}," onClick",[38,482,85],{"class":51},[38,484,485],{"class":59},"{() ",[38,487,488],{"class":51},"=>",[38,490,491],{"class":55}," setUser",[38,493,91],{"class":59},[38,495,496],{"class":55},"loginUser",[38,498,499],{"class":59},"())} \u002F>\n",[38,501,503,505,507,511,514,516],{"class":40,"line":502},20,[38,504,103],{"class":51},[38,506,106],{"class":59},[38,508,510],{"class":509},"sk71V","div",[38,512,513],{"class":59},">{user.name}\u003C\u002F",[38,515,510],{"class":509},[38,517,396],{"class":59},[38,519,521],{"class":40,"line":520},21,[38,522,133],{"class":59},[38,524,526],{"class":40,"line":525},22,[38,527,528],{"class":44},"\u002F\u002F Layout and Sidebar no longer need to know about user at all.\n",[20,530,532],{"id":531},"context-re-render-mechanics","Context Re-render Mechanics",[25,534,536],{"filename":535,"language":28},"context_renders.js",[30,537,539],{"className":32,"code":538,"language":28,"meta":34,"style":34},"\u002F\u002F CRITICAL: when the Provider's value changes, ALL consumers re-render.\n\u002F\u002F EVERY component that calls useContext(AuthContext) re-renders, regardless of\n\u002F\u002F whether it uses the part that changed.\n\n\u002F\u002F ANTI-PATTERN: new value object every render → all consumers re-render every time\nfunction App() {\n  const [user, setUser] = useState(null)\n  const [theme, setTheme] = useState('dark')  \u002F\u002F unrelated state\n  return (\n    \u003CAuthContext.Provider value={{ user, setUser }}>\n      {\u002F* Every time setTheme fires, App re-renders → { user, setUser } is a NEW\n          object → AuthContext value changes → ALL consumers re-render,\n          even though user didn't change. *\u002F}\n      \u003CLayout \u002F>\n    \u003C\u002FAuthContext.Provider>\n  )\n}\n\n\u002F\u002F FIX: memoize the value object\nfunction App() {\n  const [user, setUser] = useState(null)\n  const [theme, setTheme] = useState('dark')\n\n  const authValue = useMemo(() => ({ user, setUser }), [user])\n  \u002F\u002F setUser is stable (useState guarantees this), so deps only include user.\n  \u002F\u002F Now the value object only changes when user changes → consumers only\n  \u002F\u002F re-render when auth actually changes, not when theme toggles.\n\n  return (\n    \u003CAuthContext.Provider value={authValue}>\n      \u003CLayout \u002F>\n    \u003C\u002FAuthContext.Provider>\n  )\n}\n",[15,540,541,546,551,556,560,565,573,597,627,633,645,653,658,665,673,681,685,689,693,698,706,730,754,759,780,786,792,798,803,810,824,833,842,847],{"__ignoreMap":34},[38,542,543],{"class":40,"line":41},[38,544,545],{"class":44},"\u002F\u002F CRITICAL: when the Provider's value changes, ALL consumers re-render.\n",[38,547,548],{"class":40,"line":48},[38,549,550],{"class":44},"\u002F\u002F EVERY component that calls useContext(AuthContext) re-renders, regardless of\n",[38,552,553],{"class":40,"line":63},[38,554,555],{"class":44},"\u002F\u002F whether it uses the part that changed.\n",[38,557,558],{"class":40,"line":100},[38,559,283],{"emptyLinePlaceholder":282},[38,561,562],{"class":40,"line":130},[38,563,564],{"class":44},"\u002F\u002F ANTI-PATTERN: new value object every render → all consumers re-render every time\n",[38,566,567,569,571],{"class":40,"line":136},[38,568,52],{"class":51},[38,570,56],{"class":55},[38,572,60],{"class":59},[38,574,575,577,579,581,583,585,587,589,591,593,595],{"class":40,"line":157},[38,576,66],{"class":51},[38,578,69],{"class":59},[38,580,73],{"class":72},[38,582,76],{"class":59},[38,584,79],{"class":72},[38,586,82],{"class":59},[38,588,85],{"class":51},[38,590,88],{"class":55},[38,592,91],{"class":59},[38,594,94],{"class":72},[38,596,97],{"class":59},[38,598,599,601,603,606,608,611,613,615,617,619,622,624],{"class":40,"line":182},[38,600,66],{"class":51},[38,602,69],{"class":59},[38,604,605],{"class":72},"theme",[38,607,76],{"class":59},[38,609,610],{"class":72},"setTheme",[38,612,82],{"class":59},[38,614,85],{"class":51},[38,616,88],{"class":55},[38,618,91],{"class":59},[38,620,621],{"class":276},"'dark'",[38,623,309],{"class":59},[38,625,626],{"class":44},"\u002F\u002F unrelated state\n",[38,628,629,631],{"class":40,"line":187},[38,630,103],{"class":51},[38,632,360],{"class":59},[38,634,635,637,639,641,643],{"class":40,"line":205},[38,636,365],{"class":59},[38,638,368],{"class":72},[38,640,371],{"class":55},[38,642,85],{"class":51},[38,644,376],{"class":59},[38,646,647,650],{"class":40,"line":230},[38,648,649],{"class":59},"      {",[38,651,652],{"class":44},"\u002F* Every time setTheme fires, App re-renders → { user, setUser } is a NEW\n",[38,654,655],{"class":40,"line":235},[38,656,657],{"class":44},"          object → AuthContext value changes → ALL consumers re-render,\n",[38,659,660,663],{"class":40,"line":241},[38,661,662],{"class":44},"          even though user didn't change. *\u002F",[38,664,133],{"class":59},[38,666,667,669,671],{"class":40,"line":247},[38,668,381],{"class":59},[38,670,109],{"class":72},[38,672,386],{"class":59},[38,674,675,677,679],{"class":40,"line":408},[38,676,391],{"class":59},[38,678,368],{"class":72},[38,680,396],{"class":59},[38,682,683],{"class":40,"line":413},[38,684,401],{"class":59},[38,686,687],{"class":40,"line":419},[38,688,133],{"class":59},[38,690,691],{"class":40,"line":429},[38,692,283],{"emptyLinePlaceholder":282},[38,694,695],{"class":40,"line":457},[38,696,697],{"class":44},"\u002F\u002F FIX: memoize the value object\n",[38,699,700,702,704],{"class":40,"line":502},[38,701,52],{"class":51},[38,703,56],{"class":55},[38,705,60],{"class":59},[38,707,708,710,712,714,716,718,720,722,724,726,728],{"class":40,"line":520},[38,709,66],{"class":51},[38,711,69],{"class":59},[38,713,73],{"class":72},[38,715,76],{"class":59},[38,717,79],{"class":72},[38,719,82],{"class":59},[38,721,85],{"class":51},[38,723,88],{"class":55},[38,725,91],{"class":59},[38,727,94],{"class":72},[38,729,97],{"class":59},[38,731,732,734,736,738,740,742,744,746,748,750,752],{"class":40,"line":525},[38,733,66],{"class":51},[38,735,69],{"class":59},[38,737,605],{"class":72},[38,739,76],{"class":59},[38,741,610],{"class":72},[38,743,82],{"class":59},[38,745,85],{"class":51},[38,747,88],{"class":55},[38,749,91],{"class":59},[38,751,621],{"class":276},[38,753,97],{"class":59},[38,755,757],{"class":40,"line":756},23,[38,758,283],{"emptyLinePlaceholder":282},[38,760,762,764,767,769,772,775,777],{"class":40,"line":761},24,[38,763,66],{"class":51},[38,765,766],{"class":72}," authValue",[38,768,299],{"class":51},[38,770,771],{"class":55}," useMemo",[38,773,774],{"class":59},"(() ",[38,776,488],{"class":51},[38,778,779],{"class":59}," ({ user, setUser }), [user])\n",[38,781,783],{"class":40,"line":782},25,[38,784,785],{"class":44},"  \u002F\u002F setUser is stable (useState guarantees this), so deps only include user.\n",[38,787,789],{"class":40,"line":788},26,[38,790,791],{"class":44},"  \u002F\u002F Now the value object only changes when user changes → consumers only\n",[38,793,795],{"class":40,"line":794},27,[38,796,797],{"class":44},"  \u002F\u002F re-render when auth actually changes, not when theme toggles.\n",[38,799,801],{"class":40,"line":800},28,[38,802,283],{"emptyLinePlaceholder":282},[38,804,806,808],{"class":40,"line":805},29,[38,807,103],{"class":51},[38,809,360],{"class":59},[38,811,813,815,817,819,821],{"class":40,"line":812},30,[38,814,365],{"class":59},[38,816,368],{"class":72},[38,818,371],{"class":55},[38,820,85],{"class":51},[38,822,823],{"class":59},"{authValue}>\n",[38,825,827,829,831],{"class":40,"line":826},31,[38,828,381],{"class":59},[38,830,109],{"class":72},[38,832,386],{"class":59},[38,834,836,838,840],{"class":40,"line":835},32,[38,837,391],{"class":59},[38,839,368],{"class":72},[38,841,396],{"class":59},[38,843,845],{"class":40,"line":844},33,[38,846,401],{"class":59},[38,848,850],{"class":40,"line":849},34,[38,851,133],{"class":59},[20,853,855],{"id":854},"context-splitting-stable-vs-dynamic","Context Splitting: Stable vs Dynamic",[25,857,859],{"filename":858,"language":28},"context_splitting.js",[30,860,862],{"className":32,"code":861,"language":28,"meta":34,"style":34},"\u002F\u002F PRODUCTION PATTERN: split contexts by change frequency\n\u002F\u002F Stable values (setUser, theme config) in one context.\n\u002F\u002F Dynamic values (user object, loading state) in another.\n\nconst AuthActionsContext = createContext(null)  \u002F\u002F stable: setters, callbacks\nconst AuthStateContext = createContext(null)     \u002F\u002F dynamic: user, loading\n\nfunction AuthProvider({ children }) {\n  const [user, setUser] = useState(null)\n  const [loading, setLoading] = useState(false)\n\n  \u002F\u002F Actions are stable — setUser and setLoading are guaranteed stable by useState\n  const actions = useMemo(() => ({\n    login: async (credentials) => {\n      setLoading(true)\n      const user = await api.login(credentials)\n      setUser(user)\n      setLoading(false)\n    },\n    logout: () => setUser(null),\n  }), [])  \u002F\u002F no deps → stable forever\n\n  \u002F\u002F State changes on login\u002Flogout\n  const state = useMemo(() => ({ user, loading }), [user, loading])\n\n  return (\n    \u003CAuthActionsContext.Provider value={actions}>\n      \u003CAuthStateContext.Provider value={state}>\n        {children}\n      \u003C\u002FAuthStateContext.Provider>\n    \u003C\u002FAuthActionsContext.Provider>\n  )\n}\n\n\u002F\u002F A component that only needs login() doesn't re-render when user changes:\nfunction LoginButton() {\n  const { login } = useContext(AuthActionsContext)  \u002F\u002F stable → no re-renders from state\n  return \u003Cbutton onClick={() => login(creds)}>Log In\u003C\u002Fbutton>\n}\n\u002F\u002F A component that shows user info re-renders only when user changes:\nfunction Profile() {\n  const { user, loading } = useContext(AuthStateContext)  \u002F\u002F re-renders on user change\n  if (loading) return \u003CSpinner \u002F>\n  return \u003Cdiv>{user?.name}\u003C\u002Fdiv>\n}\n",[15,863,864,869,874,879,883,903,924,928,942,966,993,997,1002,1020,1044,1056,1077,1085,1095,1100,1119,1127,1131,1136,1154,1158,1164,1178,1192,1197,1206,1214,1218,1222,1226,1232,1242,1263,1291,1296,1302,1312,1337,1354,1370],{"__ignoreMap":34},[38,865,866],{"class":40,"line":41},[38,867,868],{"class":44},"\u002F\u002F PRODUCTION PATTERN: split contexts by change frequency\n",[38,870,871],{"class":40,"line":48},[38,872,873],{"class":44},"\u002F\u002F Stable values (setUser, theme config) in one context.\n",[38,875,876],{"class":40,"line":63},[38,877,878],{"class":44},"\u002F\u002F Dynamic values (user object, loading state) in another.\n",[38,880,881],{"class":40,"line":100},[38,882,283],{"emptyLinePlaceholder":282},[38,884,885,887,890,892,894,896,898,900],{"class":40,"line":130},[38,886,293],{"class":51},[38,888,889],{"class":72}," AuthActionsContext",[38,891,299],{"class":51},[38,893,302],{"class":55},[38,895,91],{"class":59},[38,897,94],{"class":72},[38,899,309],{"class":59},[38,901,902],{"class":44},"\u002F\u002F stable: setters, callbacks\n",[38,904,905,907,910,912,914,916,918,921],{"class":40,"line":136},[38,906,293],{"class":51},[38,908,909],{"class":72}," AuthStateContext",[38,911,299],{"class":51},[38,913,302],{"class":55},[38,915,91],{"class":59},[38,917,94],{"class":72},[38,919,920],{"class":59},")     ",[38,922,923],{"class":44},"\u002F\u002F dynamic: user, loading\n",[38,925,926],{"class":40,"line":157},[38,927,283],{"emptyLinePlaceholder":282},[38,929,930,932,935,937,940],{"class":40,"line":182},[38,931,52],{"class":51},[38,933,934],{"class":55}," AuthProvider",[38,936,144],{"class":59},[38,938,939],{"class":147},"children",[38,941,154],{"class":59},[38,943,944,946,948,950,952,954,956,958,960,962,964],{"class":40,"line":187},[38,945,66],{"class":51},[38,947,69],{"class":59},[38,949,73],{"class":72},[38,951,76],{"class":59},[38,953,79],{"class":72},[38,955,82],{"class":59},[38,957,85],{"class":51},[38,959,88],{"class":55},[38,961,91],{"class":59},[38,963,94],{"class":72},[38,965,97],{"class":59},[38,967,968,970,972,975,977,980,982,984,986,988,991],{"class":40,"line":205},[38,969,66],{"class":51},[38,971,69],{"class":59},[38,973,974],{"class":72},"loading",[38,976,76],{"class":59},[38,978,979],{"class":72},"setLoading",[38,981,82],{"class":59},[38,983,85],{"class":51},[38,985,88],{"class":55},[38,987,91],{"class":59},[38,989,990],{"class":72},"false",[38,992,97],{"class":59},[38,994,995],{"class":40,"line":230},[38,996,283],{"emptyLinePlaceholder":282},[38,998,999],{"class":40,"line":235},[38,1000,1001],{"class":44},"  \u002F\u002F Actions are stable — setUser and setLoading are guaranteed stable by useState\n",[38,1003,1004,1006,1009,1011,1013,1015,1017],{"class":40,"line":241},[38,1005,66],{"class":51},[38,1007,1008],{"class":72}," actions",[38,1010,299],{"class":51},[38,1012,771],{"class":55},[38,1014,774],{"class":59},[38,1016,488],{"class":51},[38,1018,1019],{"class":59}," ({\n",[38,1021,1022,1025,1028,1031,1033,1036,1039,1041],{"class":40,"line":247},[38,1023,1024],{"class":55},"    login",[38,1026,1027],{"class":59},": ",[38,1029,1030],{"class":51},"async",[38,1032,463],{"class":59},[38,1034,1035],{"class":147},"credentials",[38,1037,1038],{"class":59},") ",[38,1040,488],{"class":51},[38,1042,1043],{"class":59}," {\n",[38,1045,1046,1049,1051,1054],{"class":40,"line":408},[38,1047,1048],{"class":55},"      setLoading",[38,1050,91],{"class":59},[38,1052,1053],{"class":72},"true",[38,1055,97],{"class":59},[38,1057,1058,1061,1063,1065,1068,1071,1074],{"class":40,"line":413},[38,1059,1060],{"class":51},"      const",[38,1062,112],{"class":72},[38,1064,299],{"class":51},[38,1066,1067],{"class":51}," await",[38,1069,1070],{"class":59}," api.",[38,1072,1073],{"class":55},"login",[38,1075,1076],{"class":59},"(credentials)\n",[38,1078,1079,1082],{"class":40,"line":419},[38,1080,1081],{"class":55},"      setUser",[38,1083,1084],{"class":59},"(user)\n",[38,1086,1087,1089,1091,1093],{"class":40,"line":429},[38,1088,1048],{"class":55},[38,1090,91],{"class":59},[38,1092,990],{"class":72},[38,1094,97],{"class":59},[38,1096,1097],{"class":40,"line":457},[38,1098,1099],{"class":59},"    },\n",[38,1101,1102,1105,1108,1110,1112,1114,1116],{"class":40,"line":502},[38,1103,1104],{"class":55},"    logout",[38,1106,1107],{"class":59},": () ",[38,1109,488],{"class":51},[38,1111,491],{"class":55},[38,1113,91],{"class":59},[38,1115,94],{"class":72},[38,1117,1118],{"class":59},"),\n",[38,1120,1121,1124],{"class":40,"line":520},[38,1122,1123],{"class":59},"  }), [])  ",[38,1125,1126],{"class":44},"\u002F\u002F no deps → stable forever\n",[38,1128,1129],{"class":40,"line":525},[38,1130,283],{"emptyLinePlaceholder":282},[38,1132,1133],{"class":40,"line":756},[38,1134,1135],{"class":44},"  \u002F\u002F State changes on login\u002Flogout\n",[38,1137,1138,1140,1143,1145,1147,1149,1151],{"class":40,"line":761},[38,1139,66],{"class":51},[38,1141,1142],{"class":72}," state",[38,1144,299],{"class":51},[38,1146,771],{"class":55},[38,1148,774],{"class":59},[38,1150,488],{"class":51},[38,1152,1153],{"class":59}," ({ user, loading }), [user, loading])\n",[38,1155,1156],{"class":40,"line":782},[38,1157,283],{"emptyLinePlaceholder":282},[38,1159,1160,1162],{"class":40,"line":788},[38,1161,103],{"class":51},[38,1163,360],{"class":59},[38,1165,1166,1168,1171,1173,1175],{"class":40,"line":794},[38,1167,365],{"class":59},[38,1169,1170],{"class":72},"AuthActionsContext.Provider",[38,1172,371],{"class":55},[38,1174,85],{"class":51},[38,1176,1177],{"class":59},"{actions}>\n",[38,1179,1180,1182,1185,1187,1189],{"class":40,"line":800},[38,1181,381],{"class":59},[38,1183,1184],{"class":72},"AuthStateContext.Provider",[38,1186,371],{"class":55},[38,1188,85],{"class":51},[38,1190,1191],{"class":59},"{state}>\n",[38,1193,1194],{"class":40,"line":805},[38,1195,1196],{"class":59},"        {children}\n",[38,1198,1199,1202,1204],{"class":40,"line":812},[38,1200,1201],{"class":59},"      \u003C\u002F",[38,1203,1184],{"class":72},[38,1205,396],{"class":59},[38,1207,1208,1210,1212],{"class":40,"line":826},[38,1209,391],{"class":59},[38,1211,1170],{"class":72},[38,1213,396],{"class":59},[38,1215,1216],{"class":40,"line":835},[38,1217,401],{"class":59},[38,1219,1220],{"class":40,"line":844},[38,1221,133],{"class":59},[38,1223,1224],{"class":40,"line":849},[38,1225,283],{"emptyLinePlaceholder":282},[38,1227,1229],{"class":40,"line":1228},35,[38,1230,1231],{"class":44},"\u002F\u002F A component that only needs login() doesn't re-render when user changes:\n",[38,1233,1235,1237,1240],{"class":40,"line":1234},36,[38,1236,52],{"class":51},[38,1238,1239],{"class":55}," LoginButton",[38,1241,60],{"class":59},[38,1243,1245,1247,1249,1251,1253,1255,1257,1260],{"class":40,"line":1244},37,[38,1246,66],{"class":51},[38,1248,434],{"class":59},[38,1250,1073],{"class":72},[38,1252,443],{"class":59},[38,1254,85],{"class":51},[38,1256,448],{"class":55},[38,1258,1259],{"class":59},"(AuthActionsContext)  ",[38,1261,1262],{"class":44},"\u002F\u002F stable → no re-renders from state\n",[38,1264,1266,1268,1270,1273,1275,1277,1279,1281,1284,1287,1289],{"class":40,"line":1265},38,[38,1267,103],{"class":51},[38,1269,106],{"class":59},[38,1271,1272],{"class":509},"button",[38,1274,480],{"class":55},[38,1276,85],{"class":51},[38,1278,485],{"class":59},[38,1280,488],{"class":51},[38,1282,1283],{"class":55}," login",[38,1285,1286],{"class":59},"(creds)}>Log In\u003C\u002F",[38,1288,1272],{"class":509},[38,1290,396],{"class":59},[38,1292,1294],{"class":40,"line":1293},39,[38,1295,133],{"class":59},[38,1297,1299],{"class":40,"line":1298},40,[38,1300,1301],{"class":44},"\u002F\u002F A component that shows user info re-renders only when user changes:\n",[38,1303,1305,1307,1310],{"class":40,"line":1304},41,[38,1306,52],{"class":51},[38,1308,1309],{"class":55}," Profile",[38,1311,60],{"class":59},[38,1313,1315,1317,1319,1321,1323,1325,1327,1329,1331,1334],{"class":40,"line":1314},42,[38,1316,66],{"class":51},[38,1318,434],{"class":59},[38,1320,73],{"class":72},[38,1322,76],{"class":59},[38,1324,974],{"class":72},[38,1326,443],{"class":59},[38,1328,85],{"class":51},[38,1330,448],{"class":55},[38,1332,1333],{"class":59},"(AuthStateContext)  ",[38,1335,1336],{"class":44},"\u002F\u002F re-renders on user change\n",[38,1338,1340,1342,1345,1347,1349,1352],{"class":40,"line":1339},43,[38,1341,460],{"class":51},[38,1343,1344],{"class":59}," (loading) ",[38,1346,472],{"class":51},[38,1348,106],{"class":59},[38,1350,1351],{"class":72},"Spinner",[38,1353,386],{"class":59},[38,1355,1357,1359,1361,1363,1366,1368],{"class":40,"line":1356},44,[38,1358,103],{"class":51},[38,1360,106],{"class":59},[38,1362,510],{"class":509},[38,1364,1365],{"class":59},">{user?.name}\u003C\u002F",[38,1367,510],{"class":509},[38,1369,396],{"class":59},[38,1371,1373],{"class":40,"line":1372},45,[38,1374,133],{"class":59},[20,1376,1378],{"id":1377},"custom-hooks-for-context-consumption","Custom Hooks for Context Consumption",[25,1380,1382],{"filename":1381,"language":28},"custom_context_hooks.js",[30,1383,1385],{"className":32,"code":1384,"language":28,"meta":34,"style":34},"\u002F\u002F PRODUCTION PATTERN: wrap useContext in a custom hook for type safety + error checking\nfunction useAuth() {\n  const context = useContext(AuthContext)\n  if (context === undefined) {\n    throw new Error('useAuth must be used within an AuthProvider')\n    \u002F\u002F This error fires if someone uses useAuth outside \u003CAuthProvider> —\n    \u002F\u002F catches the mistake at runtime with a clear message instead of a\n    \u002F\u002F confusing null reference error deep in a consumer.\n  }\n  return context\n}\n\n\u002F\u002F Usage:\nfunction UserMenu() {\n  const { user, logout } = useAuth()  \u002F\u002F clean, self-documenting, type-safe\n  \u002F\u002F ...\n}\n\n\u002F\u002F The default value should be undefined (not null) to enable the error check:\nconst AuthContext = createContext(undefined)\n\u002F\u002F createContext(null) → context === null → the undefined check won't catch it\n\u002F\u002F createContext(undefined) → context === undefined → the check fires correctly\n",[15,1386,1387,1392,1401,1415,1431,1449,1454,1459,1464,1469,1476,1480,1484,1489,1497,1522,1527,1531,1535,1540,1557,1562],{"__ignoreMap":34},[38,1388,1389],{"class":40,"line":41},[38,1390,1391],{"class":44},"\u002F\u002F PRODUCTION PATTERN: wrap useContext in a custom hook for type safety + error checking\n",[38,1393,1394,1396,1399],{"class":40,"line":48},[38,1395,52],{"class":51},[38,1397,1398],{"class":55}," useAuth",[38,1400,60],{"class":59},[38,1402,1403,1405,1408,1410,1412],{"class":40,"line":63},[38,1404,66],{"class":51},[38,1406,1407],{"class":72}," context",[38,1409,299],{"class":51},[38,1411,448],{"class":55},[38,1413,1414],{"class":59},"(AuthContext)\n",[38,1416,1417,1419,1422,1425,1428],{"class":40,"line":100},[38,1418,460],{"class":51},[38,1420,1421],{"class":59}," (context ",[38,1423,1424],{"class":51},"===",[38,1426,1427],{"class":72}," undefined",[38,1429,1430],{"class":59},") {\n",[38,1432,1433,1436,1439,1442,1444,1447],{"class":40,"line":130},[38,1434,1435],{"class":51},"    throw",[38,1437,1438],{"class":51}," new",[38,1440,1441],{"class":55}," Error",[38,1443,91],{"class":59},[38,1445,1446],{"class":276},"'useAuth must be used within an AuthProvider'",[38,1448,97],{"class":59},[38,1450,1451],{"class":40,"line":136},[38,1452,1453],{"class":44},"    \u002F\u002F This error fires if someone uses useAuth outside \u003CAuthProvider> —\n",[38,1455,1456],{"class":40,"line":157},[38,1457,1458],{"class":44},"    \u002F\u002F catches the mistake at runtime with a clear message instead of a\n",[38,1460,1461],{"class":40,"line":182},[38,1462,1463],{"class":44},"    \u002F\u002F confusing null reference error deep in a consumer.\n",[38,1465,1466],{"class":40,"line":187},[38,1467,1468],{"class":59},"  }\n",[38,1470,1471,1473],{"class":40,"line":205},[38,1472,103],{"class":51},[38,1474,1475],{"class":59}," context\n",[38,1477,1478],{"class":40,"line":230},[38,1479,133],{"class":59},[38,1481,1482],{"class":40,"line":235},[38,1483,283],{"emptyLinePlaceholder":282},[38,1485,1486],{"class":40,"line":241},[38,1487,1488],{"class":44},"\u002F\u002F Usage:\n",[38,1490,1491,1493,1495],{"class":40,"line":247},[38,1492,52],{"class":51},[38,1494,424],{"class":55},[38,1496,60],{"class":59},[38,1498,1499,1501,1503,1505,1507,1510,1512,1514,1516,1519],{"class":40,"line":408},[38,1500,66],{"class":51},[38,1502,434],{"class":59},[38,1504,73],{"class":72},[38,1506,76],{"class":59},[38,1508,1509],{"class":72},"logout",[38,1511,443],{"class":59},[38,1513,85],{"class":51},[38,1515,1398],{"class":55},[38,1517,1518],{"class":59},"()  ",[38,1520,1521],{"class":44},"\u002F\u002F clean, self-documenting, type-safe\n",[38,1523,1524],{"class":40,"line":413},[38,1525,1526],{"class":44},"  \u002F\u002F ...\n",[38,1528,1529],{"class":40,"line":419},[38,1530,133],{"class":59},[38,1532,1533],{"class":40,"line":429},[38,1534,283],{"emptyLinePlaceholder":282},[38,1536,1537],{"class":40,"line":457},[38,1538,1539],{"class":44},"\u002F\u002F The default value should be undefined (not null) to enable the error check:\n",[38,1541,1542,1544,1546,1548,1550,1552,1555],{"class":40,"line":502},[38,1543,293],{"class":51},[38,1545,296],{"class":72},[38,1547,299],{"class":51},[38,1549,302],{"class":55},[38,1551,91],{"class":59},[38,1553,1554],{"class":72},"undefined",[38,1556,97],{"class":59},[38,1558,1559],{"class":40,"line":520},[38,1560,1561],{"class":44},"\u002F\u002F createContext(null) → context === null → the undefined check won't catch it\n",[38,1563,1564],{"class":40,"line":525},[38,1565,1566],{"class":44},"\u002F\u002F createContext(undefined) → context === undefined → the check fires correctly\n",[20,1568,1570],{"id":1569},"tips-tricks","💡 Tips & Tricks",[25,1572,1574],{"filename":1573,"language":28},"tips.js",[30,1575,1577],{"className":32,"code":1576,"language":28,"meta":34,"style":34},"\u002F\u002F [Idiom] Always wrap useContext in a custom hook (useAuth, useTheme, useCart).\n\u002F\u002F Benefits: type safety, clear error if used outside provider, self-documenting.\n\n\u002F\u002F [Performance] Memoize context values with useMemo. A new object literal\n\u002F\u002F { a, b } every render causes ALL consumers to re-render even if a and b\n\u002F\u002F haven't changed — Object.is fails on new object references.\n\n\u002F\u002F [Idiom] Split contexts by change frequency. Put stable values (setters,\n\u002F\u002F callbacks) in a separate context from dynamic values (data, loading state).\n\u002F\u002F Consumers of stable values won't re-render when dynamic values change.\n\n\u002F\u002F [Debug] If a consumer isn't getting the provider's value, check:\n\u002F\u002F 1. Is the consumer INSIDE the provider in the tree?\n\u002F\u002F 2. Is the default value undefined (to enable the \"outside provider\" error)?\n\u002F\u002F 3. Are you nesting providers correctly (outer wraps inner)?\n\n\u002F\u002F [Idiom] For context values that are just functions (dispatch, callbacks),\n\u002F\u002F useCallback each function and wrap in useMemo for the value object.\n\u002F\u002F useState setters are already stable — no need to useCallback them.\n",[15,1578,1579,1584,1589,1593,1598,1603,1608,1612,1617,1622,1627,1631,1636,1641,1646,1651,1655,1660,1665],{"__ignoreMap":34},[38,1580,1581],{"class":40,"line":41},[38,1582,1583],{"class":44},"\u002F\u002F [Idiom] Always wrap useContext in a custom hook (useAuth, useTheme, useCart).\n",[38,1585,1586],{"class":40,"line":48},[38,1587,1588],{"class":44},"\u002F\u002F Benefits: type safety, clear error if used outside provider, self-documenting.\n",[38,1590,1591],{"class":40,"line":63},[38,1592,283],{"emptyLinePlaceholder":282},[38,1594,1595],{"class":40,"line":100},[38,1596,1597],{"class":44},"\u002F\u002F [Performance] Memoize context values with useMemo. A new object literal\n",[38,1599,1600],{"class":40,"line":130},[38,1601,1602],{"class":44},"\u002F\u002F { a, b } every render causes ALL consumers to re-render even if a and b\n",[38,1604,1605],{"class":40,"line":136},[38,1606,1607],{"class":44},"\u002F\u002F haven't changed — Object.is fails on new object references.\n",[38,1609,1610],{"class":40,"line":157},[38,1611,283],{"emptyLinePlaceholder":282},[38,1613,1614],{"class":40,"line":182},[38,1615,1616],{"class":44},"\u002F\u002F [Idiom] Split contexts by change frequency. Put stable values (setters,\n",[38,1618,1619],{"class":40,"line":187},[38,1620,1621],{"class":44},"\u002F\u002F callbacks) in a separate context from dynamic values (data, loading state).\n",[38,1623,1624],{"class":40,"line":205},[38,1625,1626],{"class":44},"\u002F\u002F Consumers of stable values won't re-render when dynamic values change.\n",[38,1628,1629],{"class":40,"line":230},[38,1630,283],{"emptyLinePlaceholder":282},[38,1632,1633],{"class":40,"line":235},[38,1634,1635],{"class":44},"\u002F\u002F [Debug] If a consumer isn't getting the provider's value, check:\n",[38,1637,1638],{"class":40,"line":241},[38,1639,1640],{"class":44},"\u002F\u002F 1. Is the consumer INSIDE the provider in the tree?\n",[38,1642,1643],{"class":40,"line":247},[38,1644,1645],{"class":44},"\u002F\u002F 2. Is the default value undefined (to enable the \"outside provider\" error)?\n",[38,1647,1648],{"class":40,"line":408},[38,1649,1650],{"class":44},"\u002F\u002F 3. Are you nesting providers correctly (outer wraps inner)?\n",[38,1652,1653],{"class":40,"line":413},[38,1654,283],{"emptyLinePlaceholder":282},[38,1656,1657],{"class":40,"line":419},[38,1658,1659],{"class":44},"\u002F\u002F [Idiom] For context values that are just functions (dispatch, callbacks),\n",[38,1661,1662],{"class":40,"line":429},[38,1663,1664],{"class":44},"\u002F\u002F useCallback each function and wrap in useMemo for the value object.\n",[38,1666,1667],{"class":40,"line":457},[38,1668,1669],{"class":44},"\u002F\u002F useState setters are already stable — no need to useCallback them.\n",[20,1671,1673],{"id":1672},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[25,1675,1677],{"filename":1676,"language":28},"edge_cases.js",[30,1678,1680],{"className":32,"code":1679,"language":28,"meta":34,"style":34},"\u002F\u002F [Gotcha] The default value is used ONLY when no provider is found above the\n\u002F\u002F consumer. If a provider exists but passes value={undefined}, the consumer\n\u002F\u002F gets undefined — NOT the default. The default is a fallback for missing\n\u002F\u002F providers, not for undefined values.\n\n\u002F\u002F [Gotcha] useContext inside a component that's ABOVE the provider returns the\n\u002F\u002F default value (or throws if your custom hook checks for it). The provider\n\u002F\u002F must wrap the consumer in the component tree.\n\n\u002F\u002F [Gotcha] Context value changes cause ALL consumers to re-render — there's no\n\u002F\u002F way to opt out per-consumer. If only one field changes, every consumer that\n\u002F\u002F uses the context (even for other fields) re-renders. This is why context\n\u002F\u002F splitting (stable vs dynamic) matters for performance.\n\n\u002F\u002F [Gotcha] Nested providers of the same context: the INNERMOST provider wins.\n\u002F\u002F \u003CThemeContext.Provider value=\"dark\">\n\u002F\u002F   \u003CThemeContext.Provider value=\"light\">  ← consumers here get \"light\"\n\u002F\u002F     \u003CComponent \u002F>\n\u002F\u002F   \u003C\u002FThemeContext.Provider>\n\u002F\u002F \u003C\u002FThemeContext.Provider>\n\u002F\u002F This can be used intentionally for overrides (e.g., a dark section in a light app).\n\n\u002F\u002F [Gotcha] Context does NOT participate in bailout optimizations. Even if a\n\u002F\u002F consumer's props haven't changed and it's wrapped in React.memo, a context\n\u002F\u002F value change will still trigger a re-render. React.memo only checks props,\n\u002F\u002F not context. To prevent this, split the context so the consumer subscribes\n\u002F\u002F only to the slice it needs.\n",[15,1681,1682,1687,1692,1697,1702,1706,1711,1716,1721,1725,1730,1735,1740,1745,1749,1754,1759,1764,1769,1774,1779,1784,1788,1793,1798,1803,1808],{"__ignoreMap":34},[38,1683,1684],{"class":40,"line":41},[38,1685,1686],{"class":44},"\u002F\u002F [Gotcha] The default value is used ONLY when no provider is found above the\n",[38,1688,1689],{"class":40,"line":48},[38,1690,1691],{"class":44},"\u002F\u002F consumer. If a provider exists but passes value={undefined}, the consumer\n",[38,1693,1694],{"class":40,"line":63},[38,1695,1696],{"class":44},"\u002F\u002F gets undefined — NOT the default. The default is a fallback for missing\n",[38,1698,1699],{"class":40,"line":100},[38,1700,1701],{"class":44},"\u002F\u002F providers, not for undefined values.\n",[38,1703,1704],{"class":40,"line":130},[38,1705,283],{"emptyLinePlaceholder":282},[38,1707,1708],{"class":40,"line":136},[38,1709,1710],{"class":44},"\u002F\u002F [Gotcha] useContext inside a component that's ABOVE the provider returns the\n",[38,1712,1713],{"class":40,"line":157},[38,1714,1715],{"class":44},"\u002F\u002F default value (or throws if your custom hook checks for it). The provider\n",[38,1717,1718],{"class":40,"line":182},[38,1719,1720],{"class":44},"\u002F\u002F must wrap the consumer in the component tree.\n",[38,1722,1723],{"class":40,"line":187},[38,1724,283],{"emptyLinePlaceholder":282},[38,1726,1727],{"class":40,"line":205},[38,1728,1729],{"class":44},"\u002F\u002F [Gotcha] Context value changes cause ALL consumers to re-render — there's no\n",[38,1731,1732],{"class":40,"line":230},[38,1733,1734],{"class":44},"\u002F\u002F way to opt out per-consumer. If only one field changes, every consumer that\n",[38,1736,1737],{"class":40,"line":235},[38,1738,1739],{"class":44},"\u002F\u002F uses the context (even for other fields) re-renders. This is why context\n",[38,1741,1742],{"class":40,"line":241},[38,1743,1744],{"class":44},"\u002F\u002F splitting (stable vs dynamic) matters for performance.\n",[38,1746,1747],{"class":40,"line":247},[38,1748,283],{"emptyLinePlaceholder":282},[38,1750,1751],{"class":40,"line":408},[38,1752,1753],{"class":44},"\u002F\u002F [Gotcha] Nested providers of the same context: the INNERMOST provider wins.\n",[38,1755,1756],{"class":40,"line":413},[38,1757,1758],{"class":44},"\u002F\u002F \u003CThemeContext.Provider value=\"dark\">\n",[38,1760,1761],{"class":40,"line":419},[38,1762,1763],{"class":44},"\u002F\u002F   \u003CThemeContext.Provider value=\"light\">  ← consumers here get \"light\"\n",[38,1765,1766],{"class":40,"line":429},[38,1767,1768],{"class":44},"\u002F\u002F     \u003CComponent \u002F>\n",[38,1770,1771],{"class":40,"line":457},[38,1772,1773],{"class":44},"\u002F\u002F   \u003C\u002FThemeContext.Provider>\n",[38,1775,1776],{"class":40,"line":502},[38,1777,1778],{"class":44},"\u002F\u002F \u003C\u002FThemeContext.Provider>\n",[38,1780,1781],{"class":40,"line":520},[38,1782,1783],{"class":44},"\u002F\u002F This can be used intentionally for overrides (e.g., a dark section in a light app).\n",[38,1785,1786],{"class":40,"line":525},[38,1787,283],{"emptyLinePlaceholder":282},[38,1789,1790],{"class":40,"line":756},[38,1791,1792],{"class":44},"\u002F\u002F [Gotcha] Context does NOT participate in bailout optimizations. Even if a\n",[38,1794,1795],{"class":40,"line":761},[38,1796,1797],{"class":44},"\u002F\u002F consumer's props haven't changed and it's wrapped in React.memo, a context\n",[38,1799,1800],{"class":40,"line":782},[38,1801,1802],{"class":44},"\u002F\u002F value change will still trigger a re-render. React.memo only checks props,\n",[38,1804,1805],{"class":40,"line":788},[38,1806,1807],{"class":44},"\u002F\u002F not context. To prevent this, split the context so the consumer subscribes\n",[38,1809,1810],{"class":40,"line":794},[38,1811,1812],{"class":44},"\u002F\u002F only to the slice it needs.\n",[20,1814,1816],{"id":1815},"spot-the-bug","🧠 Spot the Bug",[1818,1819,1820],"p",{},"Every keystroke in a search input causes the entire app to re-render, even though the search state is local to one component:",[25,1822,1824],{"filename":1823,"language":28},"spot_the_bug.js",[30,1825,1827],{"className":32,"code":1826,"language":28,"meta":34,"style":34},"function App() {\n  const [user, setUser] = useState(null)\n  return (\n    \u003CAuthContext.Provider value={{ user, setUser }}>\n      \u003CSearchPage \u002F>\n    \u003C\u002FAuthContext.Provider>\n  )\n}\nfunction SearchPage() {\n  const [query, setQuery] = useState('')\n  \u002F\u002F Every keystroke → setQuery → App re-renders → { user, setUser } is a NEW\n  \u002F\u002F object → AuthContext value changes → ALL AuthContext consumers re-render.\n  return \u003Cinput value={query} onChange={e => setQuery(e.target.value)} \u002F>\n}\n",[15,1828,1829,1837,1861,1867,1879,1888,1896,1900,1904,1913,1940,1945,1950,1986],{"__ignoreMap":34},[38,1830,1831,1833,1835],{"class":40,"line":41},[38,1832,52],{"class":51},[38,1834,56],{"class":55},[38,1836,60],{"class":59},[38,1838,1839,1841,1843,1845,1847,1849,1851,1853,1855,1857,1859],{"class":40,"line":48},[38,1840,66],{"class":51},[38,1842,69],{"class":59},[38,1844,73],{"class":72},[38,1846,76],{"class":59},[38,1848,79],{"class":72},[38,1850,82],{"class":59},[38,1852,85],{"class":51},[38,1854,88],{"class":55},[38,1856,91],{"class":59},[38,1858,94],{"class":72},[38,1860,97],{"class":59},[38,1862,1863,1865],{"class":40,"line":63},[38,1864,103],{"class":51},[38,1866,360],{"class":59},[38,1868,1869,1871,1873,1875,1877],{"class":40,"line":100},[38,1870,365],{"class":59},[38,1872,368],{"class":72},[38,1874,371],{"class":55},[38,1876,85],{"class":51},[38,1878,376],{"class":59},[38,1880,1881,1883,1886],{"class":40,"line":130},[38,1882,381],{"class":59},[38,1884,1885],{"class":72},"SearchPage",[38,1887,386],{"class":59},[38,1889,1890,1892,1894],{"class":40,"line":136},[38,1891,391],{"class":59},[38,1893,368],{"class":72},[38,1895,396],{"class":59},[38,1897,1898],{"class":40,"line":157},[38,1899,401],{"class":59},[38,1901,1902],{"class":40,"line":182},[38,1903,133],{"class":59},[38,1905,1906,1908,1911],{"class":40,"line":187},[38,1907,52],{"class":51},[38,1909,1910],{"class":55}," SearchPage",[38,1912,60],{"class":59},[38,1914,1915,1917,1919,1922,1924,1927,1929,1931,1933,1935,1938],{"class":40,"line":205},[38,1916,66],{"class":51},[38,1918,69],{"class":59},[38,1920,1921],{"class":72},"query",[38,1923,76],{"class":59},[38,1925,1926],{"class":72},"setQuery",[38,1928,82],{"class":59},[38,1930,85],{"class":51},[38,1932,88],{"class":55},[38,1934,91],{"class":59},[38,1936,1937],{"class":276},"''",[38,1939,97],{"class":59},[38,1941,1942],{"class":40,"line":230},[38,1943,1944],{"class":44},"  \u002F\u002F Every keystroke → setQuery → App re-renders → { user, setUser } is a NEW\n",[38,1946,1947],{"class":40,"line":235},[38,1948,1949],{"class":44},"  \u002F\u002F object → AuthContext value changes → ALL AuthContext consumers re-render.\n",[38,1951,1952,1954,1956,1959,1961,1963,1966,1969,1971,1974,1977,1980,1983],{"class":40,"line":241},[38,1953,103],{"class":51},[38,1955,106],{"class":59},[38,1957,1958],{"class":509},"input",[38,1960,371],{"class":55},[38,1962,85],{"class":51},[38,1964,1965],{"class":59},"{query} ",[38,1967,1968],{"class":55},"onChange",[38,1970,85],{"class":51},[38,1972,1973],{"class":59},"{",[38,1975,1976],{"class":147},"e",[38,1978,1979],{"class":51}," =>",[38,1981,1982],{"class":55}," setQuery",[38,1984,1985],{"class":59},"(e.target.value)} \u002F>\n",[38,1987,1988],{"class":40,"line":247},[38,1989,133],{"class":59},[1991,1992,1993,1997,2044,2053],"details",{},[1994,1995,1996],"summary",{},"Answer",[1818,1998,1999,2000,2002,2003,2006,2007,2010,2011,2013,2014,2016,2017,2019,2020,2022,2023,2025,2026,2028,2029,2031,2032,2036,2037,2040,2041,2043],{},"The ",[15,2001,368],{}," value is ",[15,2004,2005],{},"{ user, setUser }"," — a new object literal created on every render of ",[15,2008,2009],{},"App",". When ",[15,2012,1885],{},"'s local state (",[15,2015,1921],{},") changes, it causes ",[15,2018,2009],{}," to re-render (because ",[15,2021,1885],{}," is a child of ",[15,2024,2009],{},"). On ",[15,2027,2009],{},"'s re-render, ",[15,2030,2005],{}," creates a new object reference → the context value changes → ",[2033,2034,2035],"strong",{},"all"," ",[15,2038,2039],{},"AuthContext"," consumers re-render, even though ",[15,2042,73],{}," didn't change.",[1818,2045,2046,2049,2050,2052],{},[2033,2047,2048],{},"Fix",": memoize the value object so it only changes when ",[15,2051,73],{}," changes:",[30,2054,2056],{"className":32,"code":2055,"language":28,"meta":34,"style":34},"const authValue = useMemo(() => ({ user, setUser }), [user])\n\u002F\u002F setUser is stable (useState guarantee), so deps only needs user.\n\u002F\u002F Now the context value is referentially stable across unrelated re-renders.\n",[15,2057,2058,2074,2079],{"__ignoreMap":34},[38,2059,2060,2062,2064,2066,2068,2070,2072],{"class":40,"line":41},[38,2061,293],{"class":51},[38,2063,766],{"class":72},[38,2065,299],{"class":51},[38,2067,771],{"class":55},[38,2069,774],{"class":59},[38,2071,488],{"class":51},[38,2073,779],{"class":59},[38,2075,2076],{"class":40,"line":48},[38,2077,2078],{"class":44},"\u002F\u002F setUser is stable (useState guarantee), so deps only needs user.\n",[38,2080,2081],{"class":40,"line":63},[38,2082,2083],{"class":44},"\u002F\u002F Now the context value is referentially stable across unrelated re-renders.\n",[20,2085,2087],{"id":2086},"key-takeaways","Key Takeaways",[25,2089,2091],{"filename":2090,"language":28},"key_takeaways.js",[30,2092,2094],{"className":32,"code":2093,"language":28,"meta":34,"style":34},"\u002F\u002F 1. Context solves prop drilling — provide at the top, consume anywhere below.\n\u002F\u002F    createContext(default) + Provider value={...} + useContext(context).\n\n\u002F\u002F 2. When the Provider value changes, ALL consumers re-render — no opt-out.\n\u002F\u002F    Memoize the value with useMemo to prevent unnecessary re-renders.\n\n\u002F\u002F 3. Split contexts by change frequency: stable values (setters, callbacks) in\n\u002F\u002F    one context, dynamic values (data, loading) in another. Consumers of\n\u002F\u002F    stable values don't re-render when dynamic values change.\n\n\u002F\u002F 4. Wrap useContext in a custom hook (useAuth) with an \"outside provider\" error\n\u002F\u002F    check. Use createContext(undefined) so the check can distinguish \"no provider\"\n\u002F\u002F    from \"provider with undefined value.\"\n\n\u002F\u002F 5. React.memo does NOT prevent context-triggered re-renders — memo only checks\n\u002F\u002F    props. To prevent context re-renders, split the context so the consumer\n\u002F\u002F    subscribes only to the slice it needs.\n",[15,2095,2096,2101,2106,2110,2115,2120,2124,2129,2134,2139,2143,2148,2153,2158,2162,2167,2172],{"__ignoreMap":34},[38,2097,2098],{"class":40,"line":41},[38,2099,2100],{"class":44},"\u002F\u002F 1. Context solves prop drilling — provide at the top, consume anywhere below.\n",[38,2102,2103],{"class":40,"line":48},[38,2104,2105],{"class":44},"\u002F\u002F    createContext(default) + Provider value={...} + useContext(context).\n",[38,2107,2108],{"class":40,"line":63},[38,2109,283],{"emptyLinePlaceholder":282},[38,2111,2112],{"class":40,"line":100},[38,2113,2114],{"class":44},"\u002F\u002F 2. When the Provider value changes, ALL consumers re-render — no opt-out.\n",[38,2116,2117],{"class":40,"line":130},[38,2118,2119],{"class":44},"\u002F\u002F    Memoize the value with useMemo to prevent unnecessary re-renders.\n",[38,2121,2122],{"class":40,"line":136},[38,2123,283],{"emptyLinePlaceholder":282},[38,2125,2126],{"class":40,"line":157},[38,2127,2128],{"class":44},"\u002F\u002F 3. Split contexts by change frequency: stable values (setters, callbacks) in\n",[38,2130,2131],{"class":40,"line":182},[38,2132,2133],{"class":44},"\u002F\u002F    one context, dynamic values (data, loading) in another. Consumers of\n",[38,2135,2136],{"class":40,"line":187},[38,2137,2138],{"class":44},"\u002F\u002F    stable values don't re-render when dynamic values change.\n",[38,2140,2141],{"class":40,"line":205},[38,2142,283],{"emptyLinePlaceholder":282},[38,2144,2145],{"class":40,"line":230},[38,2146,2147],{"class":44},"\u002F\u002F 4. Wrap useContext in a custom hook (useAuth) with an \"outside provider\" error\n",[38,2149,2150],{"class":40,"line":235},[38,2151,2152],{"class":44},"\u002F\u002F    check. Use createContext(undefined) so the check can distinguish \"no provider\"\n",[38,2154,2155],{"class":40,"line":241},[38,2156,2157],{"class":44},"\u002F\u002F    from \"provider with undefined value.\"\n",[38,2159,2160],{"class":40,"line":247},[38,2161,283],{"emptyLinePlaceholder":282},[38,2163,2164],{"class":40,"line":408},[38,2165,2166],{"class":44},"\u002F\u002F 5. React.memo does NOT prevent context-triggered re-renders — memo only checks\n",[38,2168,2169],{"class":40,"line":413},[38,2170,2171],{"class":44},"\u002F\u002F    props. To prevent context re-renders, split the context so the consumer\n",[38,2173,2174],{"class":40,"line":419},[38,2175,2176],{"class":44},"\u002F\u002F    subscribes only to the slice it needs.\n",[2178,2179,2180],"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 .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}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 .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}",{"title":34,"searchDepth":48,"depth":48,"links":2182},[2183,2184,2185,2186,2187,2188,2189,2190,2191],{"id":22,"depth":48,"text":23},{"id":253,"depth":48,"text":254},{"id":531,"depth":48,"text":532},{"id":854,"depth":48,"text":855},{"id":1377,"depth":48,"text":1378},{"id":1569,"depth":48,"text":1570},{"id":1672,"depth":48,"text":1673},{"id":1815,"depth":48,"text":1816},{"id":2086,"depth":48,"text":2087},"Context API, provider\u002Fconsumer patterns, re-render mechanics, context splitting for stable vs dynamic values, and custom hook idioms. Code-first reference for mid-to-senior React engineers.","md",{},"\u002Freact\u002F07-usecontext-and-prop-drilling",{"title":5,"description":2192},"react\u002F07-usecontext-and-prop-drilling","xt48oJ9ZGZonCMtnFjLt5iIahsLGL8wbmt66gT3Wlt8",1789924652098]