[{"data":1,"prerenderedAt":1475},["ShallowReactive",2],{"blog-\u002Fblog\u002Freact-usecontext-hook-guide":3},{"id":4,"title":5,"body":6,"description":1461,"difficulty":1462,"extension":1463,"framework":1464,"frameworkSlug":1465,"meta":1466,"navigation":114,"order":111,"path":1467,"qaPath":1468,"seo":1469,"stem":1470,"subtopic":57,"topic":1471,"topicSlug":1472,"updated":1473,"__hash__":1474},"blog\u002Fblog\u002Freact-usecontext-hook-guide.md","React useContext Hook — Complete Guide for Interviews",{"type":7,"value":8,"toc":1448},"minimark",[9,14,44,48,59,295,304,308,328,436,439,443,462,465,490,511,549,555,559,573,645,651,655,658,745,752,756,759,944,958,962,965,1159,1168,1172,1175,1250,1253,1257,1260,1391,1394,1398,1444],[10,11,13],"h2",{"id":12},"why-usecontext-comes-up-in-every-react-interview","Why useContext comes up in every React interview",[15,16,17,18,22,23,26,27,30,31,26,34,26,37,40,41,43],"p",{},"Context is React's built-in solution to one of the oldest frontend problems: making data\navailable to components deep in the tree without threading it through every layer. If\nyou've ever seen a codebase where a ",[19,20,21],"code",{},"user"," prop is passed from ",[19,24,25],{},"App"," → ",[19,28,29],{},"Layout"," →\n",[19,32,33],{},"Sidebar",[19,35,36],{},"Nav",[19,38,39],{},"Avatar"," when only ",[19,42,39],{}," actually uses it, you've seen the\nproblem context solves. Interviewers use context questions to probe your understanding of\nReact's data flow model, the performance model underneath the surface, and when to reach\nfor a library instead.",[10,45,47],{"id":46},"the-three-step-pattern-create-provide-consume","The three-step pattern: create, provide, consume",[15,49,50,51,54,55,58],{},"Context always involves three pieces. First you create a context object with a default\nvalue. Then a ",[19,52,53],{},"Provider"," component in the tree passes the real value down. Finally,\nany descendant calls ",[19,56,57],{},"useContext"," to read it.",[60,61,66],"pre",{"className":62,"code":63,"language":64,"meta":65,"style":65},"language-jsx shiki shiki-themes github-light github-dark","\u002F\u002F 1. create once, usually in its own file\nexport const ThemeContext = createContext('light')\n\n\u002F\u002F 2. provide high in the tree\nfunction App() {\n  const [theme, setTheme] = useState('dark')\n  return (\n    \u003CThemeContext.Provider value={theme}>\n      \u003CPage \u002F>\n    \u003C\u002FThemeContext.Provider>\n  )\n}\n\n\u002F\u002F 3. consume anywhere below\nfunction Button() {\n  const theme = useContext(ThemeContext)\n  return \u003Cbutton className={theme}>click\u003C\u002Fbutton>\n}\n","jsx","",[19,67,68,77,109,116,122,134,168,177,194,206,217,223,229,234,240,250,266,290],{"__ignoreMap":65},[69,70,73],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"sJ8bj","\u002F\u002F 1. create once, usually in its own file\n",[69,78,80,84,87,91,94,98,102,106],{"class":71,"line":79},2,[69,81,83],{"class":82},"szBVR","export",[69,85,86],{"class":82}," const",[69,88,90],{"class":89},"sj4cs"," ThemeContext",[69,92,93],{"class":82}," =",[69,95,97],{"class":96},"sScJk"," createContext",[69,99,101],{"class":100},"sVt8B","(",[69,103,105],{"class":104},"sZZnC","'light'",[69,107,108],{"class":100},")\n",[69,110,112],{"class":71,"line":111},3,[69,113,115],{"emptyLinePlaceholder":114},true,"\n",[69,117,119],{"class":71,"line":118},4,[69,120,121],{"class":75},"\u002F\u002F 2. provide high in the tree\n",[69,123,125,128,131],{"class":71,"line":124},5,[69,126,127],{"class":82},"function",[69,129,130],{"class":96}," App",[69,132,133],{"class":100},"() {\n",[69,135,137,140,143,146,149,152,155,158,161,163,166],{"class":71,"line":136},6,[69,138,139],{"class":82},"  const",[69,141,142],{"class":100}," [",[69,144,145],{"class":89},"theme",[69,147,148],{"class":100},", ",[69,150,151],{"class":89},"setTheme",[69,153,154],{"class":100},"] ",[69,156,157],{"class":82},"=",[69,159,160],{"class":96}," useState",[69,162,101],{"class":100},[69,164,165],{"class":104},"'dark'",[69,167,108],{"class":100},[69,169,171,174],{"class":71,"line":170},7,[69,172,173],{"class":82},"  return",[69,175,176],{"class":100}," (\n",[69,178,180,183,186,189,191],{"class":71,"line":179},8,[69,181,182],{"class":100},"    \u003C",[69,184,185],{"class":89},"ThemeContext.Provider",[69,187,188],{"class":96}," value",[69,190,157],{"class":82},[69,192,193],{"class":100},"{theme}>\n",[69,195,197,200,203],{"class":71,"line":196},9,[69,198,199],{"class":100},"      \u003C",[69,201,202],{"class":89},"Page",[69,204,205],{"class":100}," \u002F>\n",[69,207,209,212,214],{"class":71,"line":208},10,[69,210,211],{"class":100},"    \u003C\u002F",[69,213,185],{"class":89},[69,215,216],{"class":100},">\n",[69,218,220],{"class":71,"line":219},11,[69,221,222],{"class":100},"  )\n",[69,224,226],{"class":71,"line":225},12,[69,227,228],{"class":100},"}\n",[69,230,232],{"class":71,"line":231},13,[69,233,115],{"emptyLinePlaceholder":114},[69,235,237],{"class":71,"line":236},14,[69,238,239],{"class":75},"\u002F\u002F 3. consume anywhere below\n",[69,241,243,245,248],{"class":71,"line":242},15,[69,244,127],{"class":82},[69,246,247],{"class":96}," Button",[69,249,133],{"class":100},[69,251,253,255,258,260,263],{"class":71,"line":252},16,[69,254,139],{"class":82},[69,256,257],{"class":89}," theme",[69,259,93],{"class":82},[69,261,262],{"class":96}," useContext",[69,264,265],{"class":100},"(ThemeContext)\n",[69,267,269,271,274,278,281,283,286,288],{"class":71,"line":268},17,[69,270,173],{"class":82},[69,272,273],{"class":100}," \u003C",[69,275,277],{"class":276},"s9eBZ","button",[69,279,280],{"class":96}," className",[69,282,157],{"class":82},[69,284,285],{"class":100},"{theme}>click\u003C\u002F",[69,287,277],{"class":276},[69,289,216],{"class":100},[69,291,293],{"class":71,"line":292},18,[69,294,228],{"class":100},[15,296,297,299,300,303],{},[19,298,57],{}," replaces the older ",[19,301,302],{},"\u003CThemeContext.Consumer>"," render-prop approach with a\nsimple function call. It's always cleaner, and it composes correctly when a component\nneeds to read from multiple contexts.",[10,305,307],{"id":306},"what-the-default-value-actually-does","What the default value actually does",[15,309,310,311,314,315,319,320,323,324,327],{},"The argument to ",[19,312,313],{},"createContext"," is the default value — but it's used only when there is\n",[316,317,318],"strong",{},"no matching Provider anywhere above"," the consuming component. It does not act as a\nfallback when a Provider exists but passes ",[19,321,322],{},"undefined"," or ",[19,325,326],{},"null",".",[60,329,331],{"className":62,"code":330,"language":64,"meta":65,"style":65},"const Ctx = createContext('default')\n\n\u002F\u002F no provider -> consumer sees 'default'\nfunction Isolated() {\n  return \u003CChild \u002F>\n}\n\n\u002F\u002F provider explicitly passing undefined -> consumer sees undefined\nfunction App() {\n  return \u003CCtx.Provider value={undefined}>\u003CChild \u002F>\u003C\u002FCtx.Provider>\n}\n",[19,332,333,352,356,361,370,381,385,389,394,402,432],{"__ignoreMap":65},[69,334,335,338,341,343,345,347,350],{"class":71,"line":72},[69,336,337],{"class":82},"const",[69,339,340],{"class":89}," Ctx",[69,342,93],{"class":82},[69,344,97],{"class":96},[69,346,101],{"class":100},[69,348,349],{"class":104},"'default'",[69,351,108],{"class":100},[69,353,354],{"class":71,"line":79},[69,355,115],{"emptyLinePlaceholder":114},[69,357,358],{"class":71,"line":111},[69,359,360],{"class":75},"\u002F\u002F no provider -> consumer sees 'default'\n",[69,362,363,365,368],{"class":71,"line":118},[69,364,127],{"class":82},[69,366,367],{"class":96}," Isolated",[69,369,133],{"class":100},[69,371,372,374,376,379],{"class":71,"line":124},[69,373,173],{"class":82},[69,375,273],{"class":100},[69,377,378],{"class":89},"Child",[69,380,205],{"class":100},[69,382,383],{"class":71,"line":136},[69,384,228],{"class":100},[69,386,387],{"class":71,"line":170},[69,388,115],{"emptyLinePlaceholder":114},[69,390,391],{"class":71,"line":179},[69,392,393],{"class":75},"\u002F\u002F provider explicitly passing undefined -> consumer sees undefined\n",[69,395,396,398,400],{"class":71,"line":196},[69,397,127],{"class":82},[69,399,130],{"class":96},[69,401,133],{"class":100},[69,403,404,406,408,411,413,415,418,420,423,425,428,430],{"class":71,"line":208},[69,405,173],{"class":82},[69,407,273],{"class":100},[69,409,410],{"class":89},"Ctx.Provider",[69,412,188],{"class":96},[69,414,157],{"class":82},[69,416,417],{"class":100},"{",[69,419,322],{"class":89},[69,421,422],{"class":100},"}>\u003C",[69,424,378],{"class":89},[69,426,427],{"class":100}," \u002F>\u003C\u002F",[69,429,410],{"class":89},[69,431,216],{"class":100},[69,433,434],{"class":71,"line":219},[69,435,228],{"class":100},[15,437,438],{},"The default value is mainly useful for tests and storybook where you want to render a\nconsumer without wrapping it in the full Provider tree. Set it to a realistic value that\nmakes the component render sensibly in isolation.",[10,440,442],{"id":441},"the-performance-model-what-triggers-a-re-render","The performance model: what triggers a re-render",[15,444,445,446,449,450,457,458,461],{},"Every component that calls ",[19,447,448],{},"useContext(Ctx)"," re-renders ",[316,451,452,453,456],{},"whenever the value prop on\nthe nearest ",[19,454,455],{},"\u003CCtx.Provider>"," changes",", compared by ",[19,459,460],{},"Object.is",". This is the most\nimportant performance fact about context and the source of most context bugs in production.",[15,463,464],{},"The classic trap: putting an object literal directly in the Provider.",[60,466,468],{"className":62,"code":467,"language":64,"meta":65,"style":65},"\u002F\u002F new object on every render -> every consumer re-renders\n\u003CUserContext.Provider value={{ user, setUser }}>\n",[19,469,470,475],{"__ignoreMap":65},[69,471,472],{"class":71,"line":72},[69,473,474],{"class":75},"\u002F\u002F new object on every render -> every consumer re-renders\n",[69,476,477,480,483,485,487],{"class":71,"line":79},[69,478,479],{"class":100},"\u003C",[69,481,482],{"class":89},"UserContext.Provider",[69,484,188],{"class":96},[69,486,157],{"class":82},[69,488,489],{"class":100},"{{ user, setUser }}>\n",[15,491,492,493,496,497,499,500,502,503,506,507,510],{},"Every render of the Provider creates a fresh ",[19,494,495],{},"{}",", so ",[19,498,460],{}," sees a new value and\nall consumers re-render — even if ",[19,501,21],{}," and ",[19,504,505],{},"setUser"," haven't changed at all. Fix it\nwith ",[19,508,509],{},"useMemo",":",[60,512,514],{"className":62,"code":513,"language":64,"meta":65,"style":65},"const value = useMemo(() => ({ user, setUser }), [user])\n\u003CUserContext.Provider value={value}>\n",[19,515,516,536],{"__ignoreMap":65},[69,517,518,520,522,524,527,530,533],{"class":71,"line":72},[69,519,337],{"class":82},[69,521,188],{"class":89},[69,523,93],{"class":82},[69,525,526],{"class":96}," useMemo",[69,528,529],{"class":100},"(() ",[69,531,532],{"class":82},"=>",[69,534,535],{"class":100}," ({ user, setUser }), [user])\n",[69,537,538,540,542,544,546],{"class":71,"line":79},[69,539,479],{"class":100},[69,541,482],{"class":89},[69,543,188],{"class":96},[69,545,157],{"class":82},[69,547,548],{"class":100},"{value}>\n",[15,550,551,552,554],{},"Now consumers only re-render when ",[19,553,21],{}," actually changes.",[10,556,558],{"id":557},"reactmemo-does-not-help","React.memo does not help",[15,560,561,562,565,566,568,569,572],{},"A common misconception: wrapping a consumer in ",[19,563,564],{},"React.memo"," will protect it from\nunnecessary context re-renders. It won't. ",[19,567,564],{}," skips re-renders when ",[316,570,571],{},"props","\ndon't change, but it has no effect on context — a memoized component still re-renders\nwhen a context value it reads changes.",[60,574,576],{"className":62,"code":575,"language":64,"meta":65,"style":65},"const Avatar = React.memo(function Avatar() {\n  const { user } = useContext(UserContext) \u002F\u002F still re-renders on UserContext change\n  return \u003Cimg src={user.avatarUrl} \u002F>\n})\n",[19,577,578,601,623,640],{"__ignoreMap":65},[69,579,580,582,585,587,590,593,595,597,599],{"class":71,"line":72},[69,581,337],{"class":82},[69,583,584],{"class":89}," Avatar",[69,586,93],{"class":82},[69,588,589],{"class":100}," React.",[69,591,592],{"class":96},"memo",[69,594,101],{"class":100},[69,596,127],{"class":82},[69,598,584],{"class":96},[69,600,133],{"class":100},[69,602,603,605,608,610,613,615,617,620],{"class":71,"line":79},[69,604,139],{"class":82},[69,606,607],{"class":100}," { ",[69,609,21],{"class":89},[69,611,612],{"class":100}," } ",[69,614,157],{"class":82},[69,616,262],{"class":96},[69,618,619],{"class":100},"(UserContext) ",[69,621,622],{"class":75},"\u002F\u002F still re-renders on UserContext change\n",[69,624,625,627,629,632,635,637],{"class":71,"line":111},[69,626,173],{"class":82},[69,628,273],{"class":100},[69,630,631],{"class":276},"img",[69,633,634],{"class":96}," src",[69,636,157],{"class":82},[69,638,639],{"class":100},"{user.avatarUrl} \u002F>\n",[69,641,642],{"class":71,"line":118},[69,643,644],{"class":100},"})\n",[15,646,647,648,650],{},"The correct place to apply the optimization is the ",[316,649,53],{}," (memoize the value), not\nthe consumers.",[10,652,654],{"id":653},"splitting-context-by-change-frequency","Splitting context by change frequency",[15,656,657],{},"When one context carries both stable data and frequently-changing data, all consumers\nre-render on any change — even if they only care about the stable part. The fix is to\nsplit the context.",[60,659,661],{"className":62,"code":660,"language":64,"meta":65,"style":65},"\u002F\u002F monolithic: all consumers re-render on every notification change\n\u003CAppContext.Provider value={{ user, notifCount }}>\n\n\u002F\u002F split: UserContext consumers are unaffected by notification updates\n\u003CUserContext.Provider value={user}>\n  \u003CNotifContext.Provider value={notifCount}>\n    \u003CApp \u002F>\n  \u003C\u002FNotifContext.Provider>\n\u003C\u002FUserContext.Provider>\n",[19,662,663,668,682,686,691,704,719,727,736],{"__ignoreMap":65},[69,664,665],{"class":71,"line":72},[69,666,667],{"class":75},"\u002F\u002F monolithic: all consumers re-render on every notification change\n",[69,669,670,672,675,677,679],{"class":71,"line":79},[69,671,479],{"class":100},[69,673,674],{"class":89},"AppContext.Provider",[69,676,188],{"class":96},[69,678,157],{"class":82},[69,680,681],{"class":100},"{{ user, notifCount }}>\n",[69,683,684],{"class":71,"line":111},[69,685,115],{"emptyLinePlaceholder":114},[69,687,688],{"class":71,"line":118},[69,689,690],{"class":100},"\u002F\u002F split: UserContext consumers are unaffected by notification updates\n",[69,692,693,695,697,699,701],{"class":71,"line":124},[69,694,479],{"class":100},[69,696,482],{"class":89},[69,698,188],{"class":96},[69,700,157],{"class":82},[69,702,703],{"class":100},"{user}>\n",[69,705,706,709,712,714,716],{"class":71,"line":136},[69,707,708],{"class":100},"  \u003C",[69,710,711],{"class":89},"NotifContext.Provider",[69,713,188],{"class":96},[69,715,157],{"class":82},[69,717,718],{"class":100},"{notifCount}>\n",[69,720,721,723,725],{"class":71,"line":170},[69,722,182],{"class":100},[69,724,25],{"class":89},[69,726,205],{"class":100},[69,728,729,732,734],{"class":71,"line":179},[69,730,731],{"class":100},"  \u003C\u002F",[69,733,711],{"class":89},[69,735,216],{"class":100},[69,737,738,741,743],{"class":71,"line":196},[69,739,740],{"class":100},"\u003C\u002F",[69,742,482],{"class":89},[69,744,216],{"class":100},[15,746,747,748,751],{},"A useful heuristic: separate contexts by ",[316,749,750],{},"who cares about the change",", not by what\nmakes semantic sense together.",[10,753,755],{"id":754},"the-provider-custom-hook-pattern","The Provider + custom hook pattern",[15,757,758],{},"Rather than exporting the raw context object and letting consumers import it directly,\nencapsulate everything in a custom hook. The hook enforces correct usage and gives a\nhelpful error when a component is accidentally rendered outside its Provider.",[60,760,762],{"className":62,"code":761,"language":64,"meta":65,"style":65},"\u002F\u002F AuthContext.tsx\nconst AuthContext = createContext(null)\n\nexport function AuthProvider({ children }) {\n  const [user, setUser] = useState(null)\n  const value = useMemo(() => ({ user, setUser }), [user])\n  return \u003CAuthContext.Provider value={value}>{children}\u003C\u002FAuthContext.Provider>\n}\n\nexport function useAuth() {\n  const ctx = useContext(AuthContext)\n  if (!ctx) throw new Error('useAuth must be inside AuthProvider')\n  return ctx\n}\n",[19,763,764,769,786,790,810,834,850,870,874,878,889,903,933,940],{"__ignoreMap":65},[69,765,766],{"class":71,"line":72},[69,767,768],{"class":75},"\u002F\u002F AuthContext.tsx\n",[69,770,771,773,776,778,780,782,784],{"class":71,"line":79},[69,772,337],{"class":82},[69,774,775],{"class":89}," AuthContext",[69,777,93],{"class":82},[69,779,97],{"class":96},[69,781,101],{"class":100},[69,783,326],{"class":89},[69,785,108],{"class":100},[69,787,788],{"class":71,"line":111},[69,789,115],{"emptyLinePlaceholder":114},[69,791,792,794,797,800,803,807],{"class":71,"line":118},[69,793,83],{"class":82},[69,795,796],{"class":82}," function",[69,798,799],{"class":96}," AuthProvider",[69,801,802],{"class":100},"({ ",[69,804,806],{"class":805},"s4XuR","children",[69,808,809],{"class":100}," }) {\n",[69,811,812,814,816,818,820,822,824,826,828,830,832],{"class":71,"line":124},[69,813,139],{"class":82},[69,815,142],{"class":100},[69,817,21],{"class":89},[69,819,148],{"class":100},[69,821,505],{"class":89},[69,823,154],{"class":100},[69,825,157],{"class":82},[69,827,160],{"class":96},[69,829,101],{"class":100},[69,831,326],{"class":89},[69,833,108],{"class":100},[69,835,836,838,840,842,844,846,848],{"class":71,"line":136},[69,837,139],{"class":82},[69,839,188],{"class":89},[69,841,93],{"class":82},[69,843,526],{"class":96},[69,845,529],{"class":100},[69,847,532],{"class":82},[69,849,535],{"class":100},[69,851,852,854,856,859,861,863,866,868],{"class":71,"line":170},[69,853,173],{"class":82},[69,855,273],{"class":100},[69,857,858],{"class":89},"AuthContext.Provider",[69,860,188],{"class":96},[69,862,157],{"class":82},[69,864,865],{"class":100},"{value}>{children}\u003C\u002F",[69,867,858],{"class":89},[69,869,216],{"class":100},[69,871,872],{"class":71,"line":179},[69,873,228],{"class":100},[69,875,876],{"class":71,"line":196},[69,877,115],{"emptyLinePlaceholder":114},[69,879,880,882,884,887],{"class":71,"line":208},[69,881,83],{"class":82},[69,883,796],{"class":82},[69,885,886],{"class":96}," useAuth",[69,888,133],{"class":100},[69,890,891,893,896,898,900],{"class":71,"line":219},[69,892,139],{"class":82},[69,894,895],{"class":89}," ctx",[69,897,93],{"class":82},[69,899,262],{"class":96},[69,901,902],{"class":100},"(AuthContext)\n",[69,904,905,908,911,914,917,920,923,926,928,931],{"class":71,"line":225},[69,906,907],{"class":82},"  if",[69,909,910],{"class":100}," (",[69,912,913],{"class":82},"!",[69,915,916],{"class":100},"ctx) ",[69,918,919],{"class":82},"throw",[69,921,922],{"class":82}," new",[69,924,925],{"class":96}," Error",[69,927,101],{"class":100},[69,929,930],{"class":104},"'useAuth must be inside AuthProvider'",[69,932,108],{"class":100},[69,934,935,937],{"class":71,"line":231},[69,936,173],{"class":82},[69,938,939],{"class":100}," ctx\n",[69,941,942],{"class":71,"line":236},[69,943,228],{"class":100},[15,945,946,947,950,951,954,955,957],{},"Consumers call ",[19,948,949],{},"useAuth()"," instead of ",[19,952,953],{},"useContext(AuthContext)",". If they're outside the\nProvider, they get a clear error rather than a silent ",[19,956,326],{},". This pattern also makes it\neasy to swap the underlying implementation later without changing call sites.",[10,959,961],{"id":960},"how-to-update-context-from-a-consumer","How to update context from a consumer",[15,963,964],{},"Include the setter alongside the data in the context value. Consumers call the setter\ndirectly — it lives in the Provider's state, so calling it updates the state, causes the\nProvider to re-render, and propagates the new value to all consumers.",[60,966,968],{"className":62,"code":967,"language":64,"meta":65,"style":65},"const ThemeContext = createContext(null)\n\nfunction ThemeProvider({ children }) {\n  const [theme, setTheme] = useState('dark')\n  const value = useMemo(() => ({ theme, setTheme }), [theme])\n  return \u003CThemeContext.Provider value={value}>{children}\u003C\u002FThemeContext.Provider>\n}\n\nfunction Toggle() {\n  const { theme, setTheme } = useContext(ThemeContext)\n  return \u003Cbutton onClick={() => setTheme(t => t === 'dark' ? 'light' : 'dark')}>{theme}\u003C\u002Fbutton>\n}\n",[19,969,970,986,990,1003,1027,1044,1062,1066,1070,1079,1099,1155],{"__ignoreMap":65},[69,971,972,974,976,978,980,982,984],{"class":71,"line":72},[69,973,337],{"class":82},[69,975,90],{"class":89},[69,977,93],{"class":82},[69,979,97],{"class":96},[69,981,101],{"class":100},[69,983,326],{"class":89},[69,985,108],{"class":100},[69,987,988],{"class":71,"line":79},[69,989,115],{"emptyLinePlaceholder":114},[69,991,992,994,997,999,1001],{"class":71,"line":111},[69,993,127],{"class":82},[69,995,996],{"class":96}," ThemeProvider",[69,998,802],{"class":100},[69,1000,806],{"class":805},[69,1002,809],{"class":100},[69,1004,1005,1007,1009,1011,1013,1015,1017,1019,1021,1023,1025],{"class":71,"line":118},[69,1006,139],{"class":82},[69,1008,142],{"class":100},[69,1010,145],{"class":89},[69,1012,148],{"class":100},[69,1014,151],{"class":89},[69,1016,154],{"class":100},[69,1018,157],{"class":82},[69,1020,160],{"class":96},[69,1022,101],{"class":100},[69,1024,165],{"class":104},[69,1026,108],{"class":100},[69,1028,1029,1031,1033,1035,1037,1039,1041],{"class":71,"line":124},[69,1030,139],{"class":82},[69,1032,188],{"class":89},[69,1034,93],{"class":82},[69,1036,526],{"class":96},[69,1038,529],{"class":100},[69,1040,532],{"class":82},[69,1042,1043],{"class":100}," ({ theme, setTheme }), [theme])\n",[69,1045,1046,1048,1050,1052,1054,1056,1058,1060],{"class":71,"line":136},[69,1047,173],{"class":82},[69,1049,273],{"class":100},[69,1051,185],{"class":89},[69,1053,188],{"class":96},[69,1055,157],{"class":82},[69,1057,865],{"class":100},[69,1059,185],{"class":89},[69,1061,216],{"class":100},[69,1063,1064],{"class":71,"line":170},[69,1065,228],{"class":100},[69,1067,1068],{"class":71,"line":179},[69,1069,115],{"emptyLinePlaceholder":114},[69,1071,1072,1074,1077],{"class":71,"line":196},[69,1073,127],{"class":82},[69,1075,1076],{"class":96}," Toggle",[69,1078,133],{"class":100},[69,1080,1081,1083,1085,1087,1089,1091,1093,1095,1097],{"class":71,"line":208},[69,1082,139],{"class":82},[69,1084,607],{"class":100},[69,1086,145],{"class":89},[69,1088,148],{"class":100},[69,1090,151],{"class":89},[69,1092,612],{"class":100},[69,1094,157],{"class":82},[69,1096,262],{"class":96},[69,1098,265],{"class":100},[69,1100,1101,1103,1105,1107,1110,1112,1115,1117,1120,1122,1125,1128,1131,1134,1137,1140,1143,1146,1148,1151,1153],{"class":71,"line":219},[69,1102,173],{"class":82},[69,1104,273],{"class":100},[69,1106,277],{"class":276},[69,1108,1109],{"class":96}," onClick",[69,1111,157],{"class":82},[69,1113,1114],{"class":100},"{() ",[69,1116,532],{"class":82},[69,1118,1119],{"class":96}," setTheme",[69,1121,101],{"class":100},[69,1123,1124],{"class":805},"t",[69,1126,1127],{"class":82}," =>",[69,1129,1130],{"class":100}," t ",[69,1132,1133],{"class":82},"===",[69,1135,1136],{"class":104}," 'dark'",[69,1138,1139],{"class":82}," ?",[69,1141,1142],{"class":104}," 'light'",[69,1144,1145],{"class":82}," :",[69,1147,1136],{"class":104},[69,1149,1150],{"class":100},")}>{theme}\u003C\u002F",[69,1152,277],{"class":276},[69,1154,216],{"class":100},[69,1156,1157],{"class":71,"line":225},[69,1158,228],{"class":100},[15,1160,1161,1163,1164,1167],{},[19,1162,151],{}," has a stable identity (it's a ",[19,1165,1166],{},"useState"," setter), so including it in the\nmemoized value doesn't cause extra renders.",[10,1169,1171],{"id":1170},"context-vs-state-management-libraries","Context vs. state management libraries",[15,1173,1174],{},"Context is not a replacement for Redux, Zustand, or Jotai — it's a different tool:",[1176,1177,1178,1193],"table",{},[1179,1180,1181],"thead",{},[1182,1183,1184,1187,1190],"tr",{},[1185,1186],"th",{},[1185,1188,1189],{},"Context",[1185,1191,1192],{},"Library (Redux\u002FZustand)",[1194,1195,1196,1208,1219,1229,1239],"tbody",{},[1182,1197,1198,1202,1205],{},[1199,1200,1201],"td",{},"Re-render granularity",[1199,1203,1204],{},"All consumers of a value",[1199,1206,1207],{},"Only subscribers of the slice",[1182,1209,1210,1213,1216],{},[1199,1211,1212],{},"Selectors",[1199,1214,1215],{},"No",[1199,1217,1218],{},"Yes",[1182,1220,1221,1224,1227],{},[1199,1222,1223],{},"DevTools",[1199,1225,1226],{},"None",[1199,1228,1218],{},[1182,1230,1231,1234,1236],{},[1199,1232,1233],{},"Middleware",[1199,1235,1215],{},[1199,1237,1238],{},"Yes (thunk, saga)",[1182,1240,1241,1244,1247],{},[1199,1242,1243],{},"Good for",[1199,1245,1246],{},"Auth, theme, locale",[1199,1248,1249],{},"High-churn global state",[15,1251,1252],{},"Use context for data that changes rarely and is needed broadly — user session, theme,\nlanguage. Use a library when many components subscribe to different slices of rapidly\nchanging state, or when you need time-travel debugging and middleware.",[10,1254,1256],{"id":1255},"testing-context-consumers","Testing context consumers",[15,1258,1259],{},"Wrap the component under test in the Provider with a controlled test value. The standard\npattern is a helper render function.",[60,1261,1263],{"className":62,"code":1262,"language":64,"meta":65,"style":65},"function renderWithAuth(ui, { user = { name: 'Test' } } = {}) {\n  return render(\u003CAuthProvider initialUser={user}>{ui}\u003C\u002FAuthProvider>)\n}\n\ntest('shows username in header', () => {\n  renderWithAuth(\u003CHeader \u002F>)\n  expect(screen.getByText('Test')).toBeInTheDocument()\n})\n",[19,1264,1265,1298,1324,1328,1332,1350,1363,1387],{"__ignoreMap":65},[69,1266,1267,1269,1272,1274,1277,1280,1282,1284,1287,1290,1293,1295],{"class":71,"line":72},[69,1268,127],{"class":82},[69,1270,1271],{"class":96}," renderWithAuth",[69,1273,101],{"class":100},[69,1275,1276],{"class":805},"ui",[69,1278,1279],{"class":100},", { ",[69,1281,21],{"class":805},[69,1283,93],{"class":82},[69,1285,1286],{"class":100}," { name: ",[69,1288,1289],{"class":104},"'Test'",[69,1291,1292],{"class":100}," } } ",[69,1294,157],{"class":82},[69,1296,1297],{"class":100}," {}) {\n",[69,1299,1300,1302,1305,1308,1311,1314,1316,1319,1321],{"class":71,"line":79},[69,1301,173],{"class":82},[69,1303,1304],{"class":96}," render",[69,1306,1307],{"class":100},"(\u003C",[69,1309,1310],{"class":89},"AuthProvider",[69,1312,1313],{"class":96}," initialUser",[69,1315,157],{"class":82},[69,1317,1318],{"class":100},"{user}>{ui}\u003C\u002F",[69,1320,1310],{"class":89},[69,1322,1323],{"class":100},">)\n",[69,1325,1326],{"class":71,"line":111},[69,1327,228],{"class":100},[69,1329,1330],{"class":71,"line":118},[69,1331,115],{"emptyLinePlaceholder":114},[69,1333,1334,1337,1339,1342,1345,1347],{"class":71,"line":124},[69,1335,1336],{"class":96},"test",[69,1338,101],{"class":100},[69,1340,1341],{"class":104},"'shows username in header'",[69,1343,1344],{"class":100},", () ",[69,1346,532],{"class":82},[69,1348,1349],{"class":100}," {\n",[69,1351,1352,1355,1357,1360],{"class":71,"line":136},[69,1353,1354],{"class":96},"  renderWithAuth",[69,1356,1307],{"class":100},[69,1358,1359],{"class":89},"Header",[69,1361,1362],{"class":100}," \u002F>)\n",[69,1364,1365,1368,1371,1374,1376,1378,1381,1384],{"class":71,"line":170},[69,1366,1367],{"class":96},"  expect",[69,1369,1370],{"class":100},"(screen.",[69,1372,1373],{"class":96},"getByText",[69,1375,101],{"class":100},[69,1377,1289],{"class":104},[69,1379,1380],{"class":100},")).",[69,1382,1383],{"class":96},"toBeInTheDocument",[69,1385,1386],{"class":100},"()\n",[69,1388,1389],{"class":71,"line":179},[69,1390,644],{"class":100},[15,1392,1393],{},"Alternatively, mock the hook for unit-style tests — but a real Provider with controlled\nvalues is more robust and closer to production.",[10,1395,1397],{"id":1396},"common-interview-questions-at-a-glance","Common interview questions at a glance",[1399,1400,1401,1415,1424,1430,1438],"ul",{},[1402,1403,1404,1407,1408,1411,1412,1414],"li",{},[316,1405,1406],{},"What triggers a context consumer to re-render?"," Any change to the Provider's\n",[19,1409,1410],{},"value"," prop, compared by ",[19,1413,460],{},". New object references trigger it even if\ncontents are unchanged.",[1402,1416,1417,1423],{},[316,1418,1419,1420,1422],{},"Does ",[19,1421,564],{}," protect against context re-renders?"," No — memoize the value at\nthe Provider, not the consumer.",[1402,1425,1426,1429],{},[316,1427,1428],{},"When would you split a context?"," When different consumers care about different parts\nthat change at different frequencies.",[1402,1431,1432,1435,1436,327],{},[316,1433,1434],{},"What is the default value used for?"," When no Provider exists above the component;\nnot when a Provider passes ",[19,1437,322],{},[1402,1439,1440,1443],{},[316,1441,1442],{},"Context vs Redux?"," Context for low-churn global data; Redux\u002FZustand for\nhigh-churn data with selective subscriptions and middleware.",[1445,1446,1447],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":65,"searchDepth":79,"depth":79,"links":1449},[1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460],{"id":12,"depth":79,"text":13},{"id":46,"depth":79,"text":47},{"id":306,"depth":79,"text":307},{"id":441,"depth":79,"text":442},{"id":557,"depth":79,"text":558},{"id":653,"depth":79,"text":654},{"id":754,"depth":79,"text":755},{"id":960,"depth":79,"text":961},{"id":1170,"depth":79,"text":1171},{"id":1255,"depth":79,"text":1256},{"id":1396,"depth":79,"text":1397},"React useContext interview guide — creating and consuming context, avoiding unnecessary re-renders, splitting contexts, and when to use context vs a state library.","medium","md","React","react",{},"\u002Fblog\u002Freact-usecontext-hook-guide","\u002Freact\u002Fhooks\u002Fusecontext",{"title":5,"description":1461},"blog\u002Freact-usecontext-hook-guide","Hooks","hooks","2026-06-23","h-xTultThI-hU9VfCIKMeP4tDQ7Bj6mUVT3XMnkfVk4",1782244083369]