[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"categories-en":3,"post:\u002Fpost\u002F6-secret-useeffect-techniques":37},[4,11,17,24,30],{"id":5,"slug":6,"name":7,"colorHex":8,"iconName":9,"postCount":10},"0e2c1225-f78a-4c20-8c93-998ab9dc93b9","frontend","Frontend","#40484f",null,25,{"id":12,"slug":13,"name":14,"colorHex":15,"iconName":9,"postCount":16},"bc8df70e-b7fb-4d89-a80c-fd458d36d58c","code-development","Code & Development","#8b5cf6",23,{"id":18,"slug":19,"name":20,"colorHex":21,"iconName":22,"postCount":23},"550e8400-e29b-41d4-a716-446655440001","inteligencia-artificial","Artificial Intelligence","#6366f1","brain",14,{"id":25,"slug":26,"name":27,"colorHex":28,"iconName":9,"postCount":29},"ea63b69c-2eb4-4100-81f3-70ce52d33743","tech-news","Tech News","#e50606",4,{"id":31,"slug":32,"name":33,"colorHex":34,"iconName":35,"postCount":36},"550e8400-e29b-41d4-a716-446655440017","how-to-guides","How-To & Guides","#be123c","book-open",2,{"post":38,"related":564,"translations":629,"resolved":9},{"id":39,"slug":40,"title":41,"excerpt":42,"image":43,"featured":44,"groupId":45,"publishedAt":46,"readingTime":47,"views":48,"author":49,"category":51,"tags":52,"contentJson":59,"metaTitle":561,"metaDescription":562,"updatedAt":563},"25c0209a-404d-46d6-b163-22e1e184ca59","6-secret-useeffect-techniques","6 Secret useEffect Techniques","Beyond fetch and event listeners. What the docs show — and what they don't explain properly.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1776079320434-featured-3gqn6r.jpeg",false,"97df5bae-fb25-4753-90d9-9632e75b1c14","2026-04-13T12:48:51.27+00:00",6,0,{"name":50,"avatar":9},"Genildo Souza",{"slug":6,"name":7,"color":8},[53,56],{"slug":54,"name":55},"react","React",{"slug":57,"name":58},"javascript","JavaScript",{"type":60,"content":61},"doc",[62,70,76,95,113,120,126,132,138,146,171,177,183,195,251,272,290,297,303,313,324,329,336,351,357,363,369,374,381,387,411,418,439,444,450,461,468,483,488,509,521,527,533,536],{"type":63,"attrs":64,"content":66},"paragraph",{"id":65},"p_ev90p605",[67],{"text":68,"type":69},"useEffect is the most taught hook. And the most misunderstood. Not because the API is bad — but because most tutorials stop at the second example.","text",{"type":63,"attrs":71,"content":73},{"id":72},"p_6wuqmbd6",[74],{"text":75,"type":69},"Fetch on mount. Event listener. Dependency array with the right variable. That's the basics, and the basics are everywhere.",{"type":63,"attrs":77,"content":79},{"id":78},"p_amxu912m",[80,82,87,89,93],{"text":81,"type":69},"What's not everywhere are the six behaviors that separate those who ",{"text":83,"type":69,"marks":84},"use",[85],{"type":86},"italic",{"text":88,"type":69}," useEffect from those who ",{"text":90,"type":69,"marks":91},"understand",[92],{"type":86},{"text":94,"type":69}," useEffect.",{"type":96,"attrs":97},"archVisual",{"id":98,"cards":99,"title":9,"caption":9},"arch_ndaoqyya",[100,104,109],{"tag":101,"title":102,"subtitle":103},"Bugs avoided","6","recurring error patterns",{"tag":105,"title":106,"accent":107,"subtitle":108},"React 19","1",1,"future technique, available now",{"tag":110,"title":111,"accent":107,"subtitle":112},"Re-renders","0","unnecessary ones with Ref as escape",{"type":114,"attrs":115,"content":117},"heading",{"id":116,"level":36},"h_cgis8zcj",[118],{"text":119,"type":69},"Technique 01 — Cleanup with AbortController",{"type":63,"attrs":121,"content":123},{"id":122},"p_jljkkzza",[124],{"text":125,"type":69},"Every time a component unmounts before a fetch completes, the response still arrives — and tries to update the state of a component that no longer exists.",{"type":63,"attrs":127,"content":129},{"id":128},"p_rtx4dahq",[130],{"text":131,"type":69},"React used to warn in the console: \"Can't perform a React state update on an unmounted component\". The warning was removed in React 18. The bug remains.",{"type":133,"attrs":134},"svgDiagram",{"id":135,"svg":136,"label":137},"svg_zefj6haj","\u003Csvg viewBox=\"0 0 680 200\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" font-family=\"'Inter','Segoe UI',sans-serif\">\n  \u003Cline x1=\"40\" y1=\"100\" x2=\"640\" y2=\"100\" stroke=\"#1e2330\" stroke-width=\"2\"\u002F>\n  \u003Ccircle cx=\"80\" cy=\"100\" r=\"8\" fill=\"#3b82f6\"\u002F>\n  \u003Ctext x=\"80\" y=\"82\" text-anchor=\"middle\" font-size=\"11\" fill=\"#64748b\" font-weight=\"700\">MOUNTS\u003C\u002Ftext>\n  \u003Ctext x=\"80\" y=\"130\" text-anchor=\"middle\" font-size=\"10\" fill=\"#3b82f6\">useEffect fires\u003C\u002Ftext>\n  \u003Ccircle cx=\"200\" cy=\"100\" r=\"6\" fill=\"#06b6d4\"\u002F>\n  \u003Ctext x=\"200\" y=\"82\" text-anchor=\"middle\" font-size=\"10\" fill=\"#06b6d4\">fetch()\u003C\u002Ftext>\n  \u003Ccircle cx=\"360\" cy=\"100\" r=\"8\" fill=\"#ef4444\"\u002F>\n  \u003Ctext x=\"360\" y=\"82\" text-anchor=\"middle\" font-size=\"11\" fill=\"#64748b\" font-weight=\"700\">UNMOUNTS\u003C\u002Ftext>\n  \u003Ctext x=\"360\" y=\"130\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ef4444\">did cleanup run?\u003C\u002Ftext>\n  \u003Ccircle cx=\"520\" cy=\"100\" r=\"8\" fill=\"#ef4444\" stroke=\"#ef4444\" stroke-width=\"2\" fill-opacity=\"0.3\"\u002F>\n  \u003Ctext x=\"520\" y=\"82\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ef4444\">response arrives\u003C\u002Ftext>\n  \u003Ctext x=\"520\" y=\"130\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ef4444\">setState() 💥\u003C\u002Ftext>\n  \u003Cline x1=\"200\" y1=\"60\" x2=\"520\" y2=\"60\" stroke=\"#ef4444\" stroke-width=\"1\" stroke-dasharray=\"4 3\"\u002F>\n  \u003Cpolygon points=\"520,56 520,64 528,60\" fill=\"#ef4444\"\u002F>\n  \u003Ctext x=\"360\" y=\"52\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ef4444\">WITHOUT abort → silent bug\u003C\u002Ftext>\n  \u003Cline x1=\"200\" y1=\"155\" x2=\"360\" y2=\"155\" stroke=\"#10b981\" stroke-width=\"1.5\"\u002F>\n  \u003Cline x1=\"360\" y1=\"155\" x2=\"360\" y2=\"148\" stroke=\"#10b981\" stroke-width=\"1.5\" marker-end=\"url(#arr-en1)\"\u002F>\n  \u003Ctext x=\"280\" y=\"148\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\">WITH AbortController → cancelled ✓\u003C\u002Ftext>\n  \u003Cdefs>\n    \u003Cmarker id=\"arr-en1\" markerWidth=\"6\" markerHeight=\"6\" refX=\"3\" refY=\"3\" orient=\"auto\">\n      \u003Cpath d=\"M0,0 L0,6 L6,3 z\" fill=\"#10b981\"\u002F>\n    \u003C\u002Fmarker>\n  \u003C\u002Fdefs>\n\u003C\u002Fsvg>","Diagram — Component lifecycle with async fetch",{"type":139,"attrs":140,"content":143},"codeBlock",{"id":141,"language":57,"highlighted":142},"code_3fp5fwcj","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> UserProfile\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> [\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">user\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">setUser\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useState\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">null\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  useEffect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> controller\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> AbortController\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> fetchUser\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">() {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">      try\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> res\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> fetch\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">`\u002Fapi\u002Fusers\u002F${\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">userId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">}`\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">          signal: controller.signal,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> data\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> res.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">json\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">        setUser\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(data);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">catch\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (err) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">        if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (err.name \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> 'AbortError'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">        console.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">error\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(err);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    fetchUser\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> controller.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">abort\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }, [userId]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>{user?.name}&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[144],{"text":145,"type":69},"function UserProfile({ userId }) {\n  const [user, setUser] = useState(null);\n\n  useEffect(() => {\n    const controller = new AbortController();\n\n    async function fetchUser() {\n      try {\n        const res = await fetch(`\u002Fapi\u002Fusers\u002F${userId}`, {\n          signal: controller.signal,\n        });\n        const data = await res.json();\n        setUser(data);\n      } catch (err) {\n        if (err.name === 'AbortError') return;\n        console.error(err);\n      }\n    }\n\n    fetchUser();\n    return () => controller.abort();\n  }, [userId]);\n\n  return \u003Cdiv>{user?.name}\u003C\u002Fdiv>;\n}",{"type":147,"attrs":148,"content":151},"callout",{"id":149,"type":150,"title":9},"call_2vfm2wan","tip",[152],{"type":63,"attrs":153,"content":155},{"id":154},"p_3944kxw6",[156,158,162,164,169],{"text":157,"type":69},"The cleanup function runs when the component unmounts ",{"text":159,"type":69,"marks":160},"and",[161],{"type":86},{"text":163,"type":69}," before each new effect execution — meaning before every call with a different ",{"text":165,"type":69,"marks":166},"userId",[167],{"type":168},"code",{"text":170,"type":69},".",{"type":114,"attrs":172,"content":174},{"id":173,"level":36},"h_955mjtyy",[175],{"text":176,"type":69},"Technique 02 — The dependency array is a declaration, not a filter",{"type":63,"attrs":178,"content":180},{"id":179},"p_jsjezd7f",[181],{"text":182,"type":69},"The wrong instinct shows up like this: the effect runs too often, so the dev removes a dependency from the array to \"stop\" the extra executions. It works until it doesn't.",{"type":63,"attrs":184,"content":186},{"id":185},"p_mahxu041",[187,189,193],{"text":188,"type":69},"The dependency array tells React which values this effect uses. Not which values should trigger the effect. That distinction changes everything. Omitting a dependency doesn't silence the re-run — it creates a ",{"text":190,"type":69,"marks":191},"stale closure",[192],{"type":86},{"text":194,"type":69},": the effect gets stuck with an old snapshot of the value, and the bug surfaces non-deterministically.",{"type":196,"attrs":197,"content":199},"compare",{"id":198},"cmp_hpvcgmjl",[200,229],{"type":201,"attrs":202,"content":206},"compareColumn",{"id":203,"side":204,"title":205},"col_etoqq2o1","left","❌ Stale closure",[207],{"type":63,"attrs":208,"content":210},{"id":209},"p_yslp78hq",[211,213,215,217,218,220,221,223,224,226,227],{"text":212,"type":69},"useEffect(() => {",{"type":214},"hardBreak",{"text":216,"type":69},"  \u002F\u002F count is read here,",{"type":214},{"text":219,"type":69},"  \u002F\u002F but omitted from the array.",{"type":214},{"text":222,"type":69},"  \u002F\u002F The value never updates.",{"type":214},{"text":225,"type":69},"  document.title = `Count: ${count}`;",{"type":214},{"text":228,"type":69},"}, []); \u002F\u002F ← lying to React",{"type":201,"attrs":230,"content":234},{"id":231,"side":232,"title":233},"col_lvra8kjr","right","✅ Honest declaration",[235],{"type":63,"attrs":236,"content":238},{"id":237},"p_lpbepubq",[239,240,241,243,244,246,247,248,249],{"text":212,"type":69},{"type":214},{"text":242,"type":69},"  \u002F\u002F count is in the array.",{"type":214},{"text":245,"type":69},"  \u002F\u002F React knows when to re-run.",{"type":214},{"text":225,"type":69},{"type":214},{"text":250,"type":69},"}, [count]); \u002F\u002F ← honest contract",{"type":147,"attrs":252,"content":255},{"id":253,"type":254,"title":9},"call_3zgc6rm8","warning",[256],{"type":63,"attrs":257,"content":259},{"id":258},"p_rqy7x48j",[260,264,266,270],{"text":261,"type":69,"marks":262},"eslint-plugin-react-hooks",[263],{"type":168},{"text":265,"type":69}," catches omissions automatically. Disabling the ",{"text":267,"type":69,"marks":268},"exhaustive-deps",[269],{"type":168},{"text":271,"type":69}," rule is hiding the symptom, not treating the cause.",{"type":63,"attrs":273,"content":275},{"id":274},"p_jwfbe0uy",[276,278,282,284,288],{"text":277,"type":69},"If the effect runs too often, the real problem is usually an object or function being recreated on every render. The fix is to stabilize the values — with ",{"text":279,"type":69,"marks":280},"useCallback",[281],{"type":168},{"text":283,"type":69},", ",{"text":285,"type":69,"marks":286},"useMemo",[287],{"type":168},{"text":289,"type":69},", or by moving the definition inside the effect itself. Not omitting.",{"type":291,"attrs":292},"image",{"id":293,"alt":9,"src":294,"size":295,"align":296,"title":9,"width":9,"height":9},"img_lxt05vpt","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002F1776079069117-tzbg94.png","large","center",{"type":114,"attrs":298,"content":300},{"id":299,"level":36},"h_5l8ljbri",[301],{"text":302,"type":69},"Technique 03 — useLayoutEffect: when the DOM can't wait",{"type":63,"attrs":304,"content":306},{"id":305},"p_c58qrii4",[307,311],{"text":308,"type":69,"marks":309},"useEffect",[310],{"type":168},{"text":312,"type":69}," fires after the browser paints. Most of the time, that's exactly what you want. But there's a window between React committing changes to the DOM and the browser painting the screen.",{"type":63,"attrs":314,"content":316},{"id":315},"p_kai7s26u",[317,319,322],{"text":318,"type":69},"For tooltip positioning, layout measurements, and animations that depend on real dimensions — ",{"text":308,"type":69,"marks":320},[321],{"type":168},{"text":323,"type":69}," fires too late. The user sees the element in the wrong position before it corrects itself.",{"type":133,"attrs":325},{"id":326,"svg":327,"label":328},"svg_xxgboi3x","\u003Csvg viewBox=\"0 0 680 220\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" font-family=\"'Inter','Segoe UI',sans-serif\">\n  \u003Ctext x=\"40\" y=\"30\" font-size=\"10\" fill=\"#64748b\" font-weight=\"700\">TIME →\u003C\u002Ftext>\n  \u003Ctext x=\"40\" y=\"65\" font-size=\"11\" fill=\"#94a3b8\">useEffect\u003C\u002Ftext>\n  \u003Crect x=\"140\" y=\"52\" width=\"90\" height=\"22\" rx=\"3\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"185\" y=\"67\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">React render\u003C\u002Ftext>\n  \u003Crect x=\"240\" y=\"52\" width=\"80\" height=\"22\" rx=\"3\" fill=\"#1e3a5f\"\u002F>\n  \u003Ctext x=\"280\" y=\"67\" text-anchor=\"middle\" font-size=\"10\" fill=\"#3b82f6\">DOM commit\u003C\u002Ftext>\n  \u003Crect x=\"330\" y=\"52\" width=\"90\" height=\"22\" rx=\"3\" fill=\"#1b3a2f\"\u002F>\n  \u003Ctext x=\"375\" y=\"67\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\">Paint\u003C\u002Ftext>\n  \u003Crect x=\"430\" y=\"52\" width=\"110\" height=\"22\" rx=\"3\" fill=\"#2d1b4e\"\u002F>\n  \u003Ctext x=\"485\" y=\"67\" text-anchor=\"middle\" font-size=\"10\" fill=\"#8b5cf6\">useEffect fires\u003C\u002Ftext>\n  \u003Ctext x=\"40\" y=\"125\" font-size=\"11\" fill=\"#94a3b8\">useLayoutEffect\u003C\u002Ftext>\n  \u003Crect x=\"140\" y=\"112\" width=\"90\" height=\"22\" rx=\"3\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"185\" y=\"127\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">React render\u003C\u002Ftext>\n  \u003Crect x=\"240\" y=\"112\" width=\"80\" height=\"22\" rx=\"3\" fill=\"#1e3a5f\"\u002F>\n  \u003Ctext x=\"280\" y=\"127\" text-anchor=\"middle\" font-size=\"10\" fill=\"#3b82f6\">DOM commit\u003C\u002Ftext>\n  \u003Crect x=\"330\" y=\"112\" width=\"110\" height=\"22\" rx=\"3\" fill=\"#4c2f0a\"\u002F>\n  \u003Ctext x=\"385\" y=\"127\" text-anchor=\"middle\" font-size=\"10\" fill=\"#f59e0b\">useLayoutEffect\u003C\u002Ftext>\n  \u003Crect x=\"450\" y=\"112\" width=\"80\" height=\"22\" rx=\"3\" fill=\"#1b3a2f\"\u002F>\n  \u003Ctext x=\"490\" y=\"127\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\">Paint\u003C\u002Ftext>\n  \u003Ctext x=\"485\" y=\"100\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ef4444\">visible flash here ↑\u003C\u002Ftext>\n  \u003Ctext x=\"385\" y=\"155\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\">synchronous, before paint ✓\u003C\u002Ftext>\n  \u003Cline x1=\"40\" y1=\"95\" x2=\"640\" y2=\"95\" stroke=\"#1e2330\" stroke-width=\"1\" stroke-dasharray=\"3 4\"\u002F>\n  \u003Crect x=\"40\" y=\"170\" width=\"600\" height=\"34\" rx=\"4\" fill=\"rgba(245,158,11,0.07)\"\u002F>\n  \u003Ctext x=\"55\" y=\"191\" font-size=\"11\" fill=\"#f59e0b\">⚠  useLayoutEffect blocks paint. Don't run slow operations here.\u003C\u002Ftext>\n\u003C\u002Fsvg>","Diagram — Timing: useEffect vs useLayoutEffect",{"type":139,"attrs":330,"content":333},{"id":331,"language":57,"highlighted":332},"code_1wqnasoi","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Tooltip\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">targetRef\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">children\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> tooltipRef\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useRef\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">null\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> [\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">pos\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">setPos\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useState\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ top: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, left: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Measures BEFORE paint — no position flash\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  useLayoutEffect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">!\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">targetRef.current \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">||\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> !\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">tooltipRef.current) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> targetRect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> targetRef.current.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">getBoundingClientRect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> tooltipRect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> tooltipRef.current.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">getBoundingClientRect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    setPos\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      top: targetRect.top \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> tooltipRect.height \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">-\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 8\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      left: targetRect.left \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> targetRect.width \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> -\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> tooltipRect.width \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }, [targetRef]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ref\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{tooltipRef} \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">style\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{{ position: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'fixed'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, top: pos.top, left: pos.left }}>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      {children}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#22863A;--shiki-dark:#85E89D\">div\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[334],{"text":335,"type":69},"function Tooltip({ targetRef, children }) {\n  const tooltipRef = useRef(null);\n  const [pos, setPos] = useState({ top: 0, left: 0 });\n\n  \u002F\u002F Measures BEFORE paint — no position flash\n  useLayoutEffect(() => {\n    if (!targetRef.current || !tooltipRef.current) return;\n    const targetRect = targetRef.current.getBoundingClientRect();\n    const tooltipRect = tooltipRef.current.getBoundingClientRect();\n    setPos({\n      top: targetRect.top - tooltipRect.height - 8,\n      left: targetRect.left + targetRect.width \u002F 2 - tooltipRect.width \u002F 2,\n    });\n  }, [targetRef]);\n\n  return (\n    \u003Cdiv ref={tooltipRef} style={{ position: 'fixed', top: pos.top, left: pos.left }}>\n      {children}\n    \u003C\u002Fdiv>\n  );\n}",{"type":147,"attrs":337,"content":340},{"id":338,"type":339,"title":9},"call_ac5fc37u","info",[341],{"type":63,"attrs":342,"content":344},{"id":343},"p_sp45jxil",[345,349],{"text":346,"type":69,"marks":347},"useLayoutEffect",[348],{"type":168},{"text":350,"type":69}," is synchronous and blocks paint. Reserve it for DOM measurements and positioning. Slow operations here will freeze the UI.",{"type":114,"attrs":352,"content":354},{"id":353,"level":36},"h_jbcwtm05",[355],{"text":356,"type":69},"Technique 04 — Refs as dependency escape hatches",{"type":63,"attrs":358,"content":360},{"id":359},"p_42f0z7eq",[361],{"text":362,"type":69},"Callback functions come as props. When you need to call them inside an effect, the linter requires them in the dependency array. But callbacks recreated on every render make the effect re-run for no real reason.",{"type":63,"attrs":364,"content":366},{"id":365},"p_qdwclfm4",[367],{"text":368,"type":69},"The ref is the way out: it stores the latest value without making the effect depend on it.",{"type":133,"attrs":370},{"id":371,"svg":372,"label":373},"svg_yitwfynv","\u003Csvg viewBox=\"0 0 680 180\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" font-family=\"'Inter','Segoe UI',sans-serif\">\n  \u003Ctext x=\"40\" y=\"30\" font-size=\"11\" fill=\"#ef4444\" font-weight=\"700\">A) Direct dependency — unnecessary re-runs\u003C\u002Ftext>\n  \u003Crect x=\"40\" y=\"42\" width=\"100\" height=\"30\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"90\" y=\"61\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 1\u003C\u002Ftext>\n  \u003Crect x=\"160\" y=\"42\" width=\"100\" height=\"30\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"210\" y=\"61\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 2\u003C\u002Ftext>\n  \u003Crect x=\"280\" y=\"42\" width=\"100\" height=\"30\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"330\" y=\"61\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 3\u003C\u002Ftext>\n  \u003Cline x1=\"140\" y1=\"57\" x2=\"160\" y2=\"57\" stroke=\"#ef4444\" stroke-width=\"1\"\u002F>\n  \u003Ctext x=\"150\" y=\"50\" text-anchor=\"middle\" font-size=\"9\" fill=\"#ef4444\">re-run\u003C\u002Ftext>\n  \u003Cline x1=\"260\" y1=\"57\" x2=\"280\" y2=\"57\" stroke=\"#ef4444\" stroke-width=\"1\"\u002F>\n  \u003Ctext x=\"270\" y=\"50\" text-anchor=\"middle\" font-size=\"9\" fill=\"#ef4444\">re-run\u003C\u002Ftext>\n  \u003Ctext x=\"400\" y=\"61\" font-size=\"10\" fill=\"#ef4444\">... and so on\u003C\u002Ftext>\n  \u003Cline x1=\"40\" y1=\"95\" x2=\"640\" y2=\"95\" stroke=\"#1e2330\" stroke-width=\"1\" stroke-dasharray=\"3 4\"\u002F>\n  \u003Ctext x=\"40\" y=\"115\" font-size=\"11\" fill=\"#10b981\" font-weight=\"700\">B) Via ref — stable effect\u003C\u002Ftext>\n  \u003Crect x=\"40\" y=\"127\" width=\"100\" height=\"30\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"90\" y=\"146\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 1\u003C\u002Ftext>\n  \u003Crect x=\"160\" y=\"127\" width=\"100\" height=\"30\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"210\" y=\"146\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 2\u003C\u002Ftext>\n  \u003Crect x=\"280\" y=\"127\" width=\"100\" height=\"30\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"330\" y=\"146\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 3\u003C\u002Ftext>\n  \u003Crect x=\"420\" y=\"120\" width=\"120\" height=\"44\" rx=\"4\" fill=\"rgba(16,185,129,0.1)\" stroke=\"#10b981\" stroke-width=\"1\"\u002F>\n  \u003Ctext x=\"480\" y=\"138\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\" font-weight=\"700\">callbackRef\u003C\u002Ftext>\n  \u003Ctext x=\"480\" y=\"155\" text-anchor=\"middle\" font-size=\"9\" fill=\"#64748b\">always up to date\u003C\u002Ftext>\n  \u003Cline x1=\"140\" y1=\"142\" x2=\"420\" y2=\"142\" stroke=\"#10b981\" stroke-width=\"1\" stroke-dasharray=\"3 3\"\u002F>\n  \u003Ctext x=\"590\" y=\"115\" font-size=\"10\" fill=\"#10b981\">effect: runs 1x ✓\u003C\u002Ftext>\n\u003C\u002Fsvg>","Diagram — Callback via ref vs. direct dependency",{"type":139,"attrs":375,"content":378},{"id":376,"language":57,"highlighted":377},"code_mags74lu","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useInterval\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">callback\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">delay\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Ref always holds the latest version of the callback\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> savedCallback\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useRef\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(callback);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F Updates the ref without re-running the effect\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  useEffect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    savedCallback.current \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> callback;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }, [callback]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F The interval uses the ref — deps array only needs [delay]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  useEffect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    if\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (delay \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> null\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> id\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> setInterval\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">      savedCallback.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">current\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F reads latest value via ref\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    }, delay);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> clearInterval\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(id);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }, [delay]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[379],{"text":380,"type":69},"function useInterval(callback, delay) {\n  \u002F\u002F Ref always holds the latest version of the callback\n  const savedCallback = useRef(callback);\n\n  \u002F\u002F Updates the ref without re-running the effect\n  useEffect(() => {\n    savedCallback.current = callback;\n  }, [callback]);\n\n  \u002F\u002F The interval uses the ref — deps array only needs [delay]\n  useEffect(() => {\n    if (delay === null) return;\n    const id = setInterval(() => {\n      savedCallback.current(); \u002F\u002F reads latest value via ref\n    }, delay);\n    return () => clearInterval(id);\n  }, [delay]);\n}",{"type":114,"attrs":382,"content":384},{"id":383,"level":36},"h_ewcvp0b9",[385],{"text":386,"type":69},"Technique 05 — useEffectEvent: reading state without depending on it",{"type":63,"attrs":388,"content":390},{"id":389},"p_ppj1fost",[391,393,397,399,403,405,409],{"text":392,"type":69},"An effect needs to react to a change — ",{"text":394,"type":69,"marks":395},"roomId",[396],{"type":168},{"text":398,"type":69}," — but inside it, needs to read a current value — ",{"text":400,"type":69,"marks":401},"theme",[402],{"type":168},{"text":404,"type":69}," — without that value causing re-execution. React 19 introduced ",{"text":406,"type":69,"marks":407},"useEffectEvent",[408],{"type":168},{"text":410,"type":69}," to formalize this separation between reactive and non-reactive code.",{"type":139,"attrs":412,"content":415},{"id":413,"language":57,"highlighted":414},"code_kxfwtvji","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">import\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { experimental_useEffectEvent \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">as\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> useEffectEvent } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> 'react'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> ChatRoom\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">roomId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">theme\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F onConnected reads theme internally, but doesn't depend on it\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> onConnected\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useEffectEvent\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    showNotification\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">`Connected to room ${\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">roomId\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">}`\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, theme);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  });\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  useEffect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> connection\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> createConnection\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(roomId);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    connection.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">on\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'connected'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> onConnected\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">());\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    connection.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">connect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> connection.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">disconnect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }, [roomId]); \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F theme doesn't need to be here\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[416],{"text":417,"type":69},"import { experimental_useEffectEvent as useEffectEvent } from 'react';\n\nfunction ChatRoom({ roomId, theme }) {\n  \u002F\u002F onConnected reads theme internally, but doesn't depend on it\n  const onConnected = useEffectEvent(() => {\n    showNotification(`Connected to room ${roomId}`, theme);\n  });\n\n  useEffect(() => {\n    const connection = createConnection(roomId);\n    connection.on('connected', () => onConnected());\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]); \u002F\u002F theme doesn't need to be here\n}",{"type":147,"attrs":419,"content":421},{"id":420,"type":339,"title":9},"call_tlqt4b00",[422],{"type":63,"attrs":423,"content":425},{"id":424},"p_m48oq6e1",[426,428,431,433,437],{"text":427,"type":69},"Status as of April 2026: ",{"text":406,"type":69,"marks":429},[430],{"type":168},{"text":432,"type":69}," is still canary\u002Fexperimental. In production, use the ",{"text":434,"type":69,"marks":435},"useRef",[436],{"type":168},{"text":438,"type":69}," pattern from technique 04. Same concept — the API will stabilize.",{"type":133,"attrs":440},{"id":441,"svg":442,"label":443},"svg_hdqmz0b4","\u003Csvg viewBox=\"0 0 680 160\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" font-family=\"'Inter','Segoe UI',sans-serif\">\n  \u003Crect x=\"40\" y=\"30\" width=\"240\" height=\"100\" rx=\"6\" fill=\"rgba(59,130,246,0.08)\" stroke=\"#3b82f6\" stroke-width=\"1.5\"\u002F>\n  \u003Ctext x=\"160\" y=\"52\" text-anchor=\"middle\" font-size=\"11\" fill=\"#3b82f6\" font-weight=\"700\">useEffect\u003C\u002Ftext>\n  \u003Ctext x=\"160\" y=\"74\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">reacts to: [roomId]\u003C\u002Ftext>\n  \u003Ctext x=\"160\" y=\"92\" text-anchor=\"middle\" font-size=\"10\" fill=\"#64748b\">connect \u002F disconnect\u003C\u002Ftext>\n  \u003Ctext x=\"160\" y=\"114\" text-anchor=\"middle\" font-size=\"10\" fill=\"#64748b\">reactive by nature\u003C\u002Ftext>\n  \u003Cline x1=\"280\" y1=\"80\" x2=\"360\" y2=\"80\" stroke=\"#1e2330\" stroke-width=\"1.5\" marker-end=\"url(#arr-en4)\"\u002F>\n  \u003Ctext x=\"320\" y=\"73\" text-anchor=\"middle\" font-size=\"10\" fill=\"#64748b\">calls\u003C\u002Ftext>\n  \u003Cdefs>\n    \u003Cmarker id=\"arr-en4\" markerWidth=\"6\" markerHeight=\"6\" refX=\"3\" refY=\"3\" orient=\"auto\">\n      \u003Cpath d=\"M0,0 L0,6 L6,3 z\" fill=\"#1e2330\"\u002F>\n    \u003C\u002Fmarker>\n  \u003C\u002Fdefs>\n  \u003Crect x=\"360\" y=\"30\" width=\"280\" height=\"100\" rx=\"6\" fill=\"rgba(139,92,246,0.08)\" stroke=\"#8b5cf6\" stroke-width=\"1.5\"\u002F>\n  \u003Ctext x=\"500\" y=\"52\" text-anchor=\"middle\" font-size=\"11\" fill=\"#8b5cf6\" font-weight=\"700\">useEffectEvent\u003C\u002Ftext>\n  \u003Ctext x=\"500\" y=\"74\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">reads: theme (always current)\u003C\u002Ftext>\n  \u003Ctext x=\"500\" y=\"92\" text-anchor=\"middle\" font-size=\"10\" fill=\"#64748b\">showNotification()\u003C\u002Ftext>\n  \u003Ctext x=\"500\" y=\"114\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\">non-reactive — no re-run ✓\u003C\u002Ftext>\n\u003C\u002Fsvg>","Diagram — Reactive vs. non-reactive separation",{"type":114,"attrs":445,"content":447},{"id":446,"level":36},"h_smifz50p",[448],{"text":449,"type":69},"Technique 06 — useEffect doesn't manage derived state",{"type":63,"attrs":451,"content":453},{"id":452},"p_2xfbxwik",[454,456,459],{"text":455,"type":69},"This is the most common silent mistake. The code works. Tests pass. And yet there's an extra render every time — plus a ",{"text":308,"type":69,"marks":457},[458],{"type":168},{"text":460,"type":69}," that shouldn't exist.",{"type":139,"attrs":462,"content":465},{"id":463,"language":57,"highlighted":464},"code_b75craeb","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ❌ Effect to derive state — causes double render\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> FilteredList\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">items\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">query\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> [\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">filtered\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">setFiltered\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useState\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">([]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  useEffect\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(() \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">    setFiltered\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(items.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">filter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">item\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> item.name.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">includes\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(query)));\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  }, [items, query]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">List\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> items\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{filtered} \u002F>;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F ✅ Calculated during render — correct and no overhead\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> FilteredList\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">items\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">query\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> filtered\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> useMemo\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    () \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> items.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">filter\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\">item\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> item.name.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">includes\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(query)),\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">    [items, query]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">  );\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> &#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">List\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> items\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">{filtered} \u002F>;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",[466],{"text":467,"type":69},"\u002F\u002F ❌ Effect to derive state — causes double render\nfunction FilteredList({ items, query }) {\n  const [filtered, setFiltered] = useState([]);\n  useEffect(() => {\n    setFiltered(items.filter(item => item.name.includes(query)));\n  }, [items, query]);\n  return \u003CList items={filtered} \u002F>;\n}\n\n\u002F\u002F ✅ Calculated during render — correct and no overhead\nfunction FilteredList({ items, query }) {\n  const filtered = useMemo(\n    () => items.filter(item => item.name.includes(query)),\n    [items, query]\n  );\n  return \u003CList items={filtered} \u002F>;\n}",{"type":63,"attrs":469,"content":471},{"id":470},"p_wv64uf69",[472,475,477,481],{"text":308,"type":69,"marks":473},[474],{"type":168},{"text":476,"type":69}," exists to synchronize React with external systems: APIs, WebSockets, timers, ",{"text":478,"type":69,"marks":479},"localStorage",[480],{"type":168},{"text":482,"type":69},", third-party libraries. Not to transform data that's already inside React.",{"type":133,"attrs":484},{"id":485,"svg":486,"label":487},"svg_ruqzfcw0","\u003Csvg viewBox=\"0 0 680 160\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" font-family=\"'Inter','Segoe UI',sans-serif\">\n  \u003Ctext x=\"40\" y=\"30\" font-size=\"11\" fill=\"#ef4444\" font-weight=\"700\">useState + useEffect\u003C\u002Ftext>\n  \u003Crect x=\"40\" y=\"42\" width=\"120\" height=\"36\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"100\" y=\"57\" text-anchor=\"middle\" font-size=\"10\" fill=\"#94a3b8\">Render 1\u003C\u002Ftext>\n  \u003Ctext x=\"100\" y=\"70\" text-anchor=\"middle\" font-size=\"9\" fill=\"#ef4444\">stale list\u003C\u002Ftext>\n  \u003Cline x1=\"160\" y1=\"60\" x2=\"200\" y2=\"60\" stroke=\"#ef4444\" stroke-width=\"1.5\"\u002F>\n  \u003Cpolygon points=\"200,56 200,64 208,60\" fill=\"#ef4444\"\u002F>\n  \u003Crect x=\"208\" y=\"42\" width=\"120\" height=\"36\" rx=\"4\" fill=\"#1e2330\"\u002F>\n  \u003Ctext x=\"268\" y=\"57\" text-anchor=\"middle\" font-size=\"10\" fill=\"#ef4444\">Render 2\u003C\u002Ftext>\n  \u003Ctext x=\"268\" y=\"70\" text-anchor=\"middle\" font-size=\"9\" fill=\"#10b981\">correct list (now)\u003C\u002Ftext>\n  \u003Ctext x=\"360\" y=\"63\" font-size=\"10\" fill=\"#ef4444\">= 2 renders per query change\u003C\u002Ftext>\n  \u003Cline x1=\"40\" y1=\"100\" x2=\"640\" y2=\"100\" stroke=\"#1e2330\" stroke-width=\"1\" stroke-dasharray=\"3 4\"\u002F>\n  \u003Ctext x=\"40\" y=\"120\" font-size=\"11\" fill=\"#10b981\" font-weight=\"700\">useMemo in render\u003C\u002Ftext>\n  \u003Crect x=\"40\" y=\"132\" width=\"160\" height=\"18\" rx=\"4\" fill=\"rgba(16,185,129,0.1)\" stroke=\"#10b981\" stroke-width=\"1\"\u002F>\n  \u003Ctext x=\"120\" y=\"145\" text-anchor=\"middle\" font-size=\"10\" fill=\"#10b981\">Single render — correct ✓\u003C\u002Ftext>\n  \u003Ctext x=\"250\" y=\"145\" font-size=\"10\" fill=\"#64748b\">= 1 render per query change\u003C\u002Ftext>\n\u003C\u002Fsvg>","Diagram — Render count comparison",{"type":147,"attrs":489,"content":491},{"id":490,"type":339,"title":9},"call_c5j55mpl",[492],{"type":63,"attrs":493,"content":495},{"id":494},"p_iwocyyfd",[496,498,501,503,507],{"text":497,"type":69},"Quick test: any ",{"text":308,"type":69,"marks":499},[500],{"type":168},{"text":502,"type":69}," that starts with ",{"text":504,"type":69,"marks":505},"setSomeState(...)",[506],{"type":168},{"text":508,"type":69}," deserves suspicion. Ask first: could this calculation happen during render?",{"type":510,"attrs":511},"summaryBox",{"id":512,"items":513,"title":520},"sum_kw2wts12",[514,515,516,517,518,519],"Every fetch inside useEffect has an AbortController — no exceptions.","The dependency array is honest. When it's uncomfortable, the problem is the value being recreated, not the eslint rule.","DOM measurements and positioning use useLayoutEffect, not useEffect.","Prop callbacks inside effects are stabilized via ref or useCallback.","useEffectEvent separates what reacts to the outside world from what just reads internal state.","Derived state is calculated during render. useEffect is not a data transformer.","What changes in your code from now on",{"type":63,"attrs":522,"content":524},{"id":523},"p_i04c27ak",[525],{"text":526,"type":69},"useEffect hasn't changed much since React 16.8. What changed is the understanding of what it actually is: a synchronization layer between React and the external world.",{"type":63,"attrs":528,"content":530},{"id":529},"p_j3efgp63",[531],{"text":532,"type":69},"Everything that doesn't need the external world — doesn't belong there.",{"type":63,"attrs":534},{"id":535},"p_evkiwibu",{"type":537,"attrs":538},"quiz",{"id":539,"questions":540},"quiz-useeffect",[541,547,554],{"correct":542,"options":543,"question":545,"explanation":546},"AbortController",[542,544,285],"setTimeout","Which API does the article recommend for cancelling requests in the useEffect cleanup?","Technique 01 uses AbortController in the cleanup to cancel stale fetches.",{"correct":548,"options":549,"question":552,"explanation":553},"A declaration, not a filter",[550,548,551],"A render filter","An optional optimization","According to the article, the dependency array is...","Technique 02: the array declares everything the effect reads; it is not for filtering runs.",{"correct":555,"options":556,"question":559,"explanation":560},"When the DOM cannot wait (measure\u002Fmutate before paint)",[555,557,558],"Always, because it is faster","To fetch data from APIs","When should you use useLayoutEffect instead of useEffect?","Technique 03: useLayoutEffect runs before paint, ideal for measurements and visual mutations.","6 Secret useEffect Techniques | Blueprint Blog","Master useEffect beyond the basics: AbortController, stale closures, useLayoutEffect, Refs as escape hatches, useEffectEvent and derived state.","2026-08-24T14:53:53.315534+00:00",[565,583,596,610],{"id":566,"slug":567,"title":568,"excerpt":569,"image":570,"featured":44,"groupId":571,"publishedAt":572,"readingTime":573,"views":48,"author":574,"category":575,"tags":576},"841890b2-1a8c-43d4-b434-b94714705605","debugging-css-the-forgotten-margin-and-frontend-lessons","Debugging CSS: The Forgotten Margin and Frontend Lessons","A forgotten CSS property turned a minor layout glitch into a two-week ordeal. Learn how to avoid emotional debugging and fix complex UI issues faster.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1767745741814-featured-i6p1gc.jpeg","bcaf503a-15c1-4d28-8795-6ae3c2a3e06f","2026-08-02T16:09:35.153874+00:00",8,{"name":50,"avatar":9},{"slug":6,"name":7,"color":8},[577,580],{"slug":578,"name":579},"css","CSS",{"slug":581,"name":582},"performance","Performance",{"id":584,"slug":585,"title":586,"excerpt":587,"image":588,"featured":44,"groupId":589,"publishedAt":590,"readingTime":23,"views":48,"author":591,"category":592,"tags":593},"d5167910-cc5b-4fae-a2e8-d09adcf354b2","stop-using-usememo-wrong-a-practical-guide-to-react-performance","Stop Using useMemo Wrong: A Practical Guide to React Performance","Master React useMemo with this guide. Learn when to memoize, how to fix dependency array bugs, and why over-optimization can hurt your performance.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1769657096789-featured-r2q2sb.jpeg","a1c571c1-aa37-404d-ac67-f265c8a9985b","2026-07-08T23:34:34.563653+00:00",{"name":50,"avatar":9},{"slug":6,"name":7,"color":8},[594,595],{"slug":57,"name":58},{"slug":54,"name":55},{"id":597,"slug":598,"title":599,"excerpt":600,"image":601,"featured":44,"groupId":602,"publishedAt":603,"readingTime":604,"views":48,"author":605,"category":606,"tags":607},"f1b5af43-20da-4150-a7c7-ef17675d1fee","css-animations-how-to-build-performant-professional-interfaces-without-messy-code","CSS Animations: How to Build Performant, Professional Interfaces Without Messy Code","Bring your web interfaces to life. Learn when to use CSS transitions versus keyframes and how to optimize your animations for peak performance.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1770952624247-featured-in9pir.jpeg","de5a7726-1227-4080-b572-9d91a37b207b","2026-07-04T03:00:53.174696+00:00",17,{"name":50,"avatar":9},{"slug":6,"name":7,"color":8},[608,609],{"slug":578,"name":579},{"slug":581,"name":582},{"id":611,"slug":612,"title":613,"excerpt":614,"image":615,"featured":44,"groupId":616,"publishedAt":617,"readingTime":618,"views":48,"author":619,"category":620,"tags":621},"86e804a8-71f4-4985-a013-d6c033e28967","angular-micro-frontends-how-to-scale-large-applications-and-eliminate-monolithic-build-times-with-module-federation","Angular Micro-frontends: How to Scale Large Applications and Eliminate Monolithic Build Times with Module Federation","Discover how to break down large Angular monoliths using Module Federation to enable independent deployments and seamless team scaling.","https:\u002F\u002Fmfgiomkkbihnlpfdxwrt.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fblog-assets\u002Fmedia\u002Ffeatured\u002F1774499855857-featured-x9ugz1.jpg","a029aa9b-573b-4e5b-921b-eaecea6e989f","2026-06-21T06:41:59.230237+00:00",10,{"name":50,"avatar":9},{"slug":6,"name":7,"color":8},[622,625,626],{"slug":623,"name":624},"angular","Angular",{"slug":57,"name":58},{"slug":627,"name":628},"typescript","TypeScript",{"pt":630,"es":631,"en":40},"domine-o-useeffect-6-padroes-para-eliminar-bugs-e-renders-desnecessarios","6-tecnicas-secretas-del-useeffect"]