PageSourceSearch

https://simoneamico.com/assets/js/3687a708.d2b33878.js

js simoneamico.com collected 2026-10-09 00:14:31 UTC 31,674 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkmotore_temp=globalThis.webpackChunkmotore_temp||[]).push([[5247],{1470:(e,t,n)=>{n.d(t,{A:()=>I});var s=n(6540),r=n(4164),i=n(7559),a=n(3104),o=n(6347),c=n(205),l=n(7485),h=n(1682),d=n(679);function u(e){return s.Children.toArray(e).filter(e=>"\n"!==e).map(e=>{if(!e||(0,s.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)})?.filter(Boolean)??[]}function m(e){const{values:t,children:n}=e;return(0,s.useMemo)(()=>{const e=t??function(e){return u(e).map(({props:{value:e,label:t,attributes:n,default:s}})=>({value:e,label:t,attributes:n,default:s}))}(n);return function(e){const t=(0,h.XI)(e,(e,t)=>e.value===t.value);if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map(e=>e.value).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e},[t,n])}function p({value:e,tabValues:t}){return t.some(t=>t.value===e)}function f({queryString:e=!1,groupId:t}){const n=(0,o.W6)(),r=function({queryString:e=!1,groupId:t}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!t)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:e,groupId:t});return[(0,l.aZ)(r),(0,s.useCallback)(e=>{if(!r)return;const t=new URLSearchParams(n.location.search);t.set(r,e),n.replace({...n.location,search:t.toString()})},[r,n])]}function g(e){const{defaultValue:t,queryString:n=!1,groupId:r}=e,i=m(e),[a,o]=(0,s.useState)(()=>function({defaultValue:e,tabValues:t}){if(0===t.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!p({value:e,tabValues:t}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${t.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}const n=t.find(e=>e.default)??t[0];if(!n)throw new Error("Unexpected error: 0 tabValues");return n.value}({defaultValue:t,tabValues:i})),[l,h]=f({queryString:n,groupId:r}),[u,g]=function({groupId:e}){const t=function(e){return e?`docusaurus.tab.${e}`:null}(e),[n,r]=(0,d.Dv)(t);return[n,(0,s.useCallback)(e=>{t&&r.set(e)},[t,r])]}({groupId:r}),x=(()=>{const e=l??u;return p({value:e,tabValues:i})?e:null})();(0,c.A)(()=>{x&&o(x)},[x]);return{selectedValue:a,selectValue:(0,s.useCallback)(e=>{if(!p({value:e,tabValues:i}))throw new Error(`Can't select invalid tab value=${e}`);o(e),h(e),g(e)},[h,g,i]),tabValues:i}}var x=n(2303);const b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var y=n(4848);function w({className:e,block:t,selectedValue:n,selectValue:s,tabValues:i}){const o=[],{blockElementScrollPositionUntilNextRender:c}=(0,a.a_)(),l=e=>{const t=e.currentTarget,r=o.indexOf(t),a=i[r].value;a!==n&&(c(t),s(a))},h=e=>{let t=null;switch(e.key){case"Enter":l(e);break;case"ArrowRight":{const n=o.indexOf(e.currentTarget)+1;t=o[n]??o[0];break}case"ArrowLeft":{const n=o.indexOf(e.currentTarget)-1;t=o[n]??o[o.length-1];break}}t?.focus()};return(0,y.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":t},e),children:i.map(({value:e,label:t,attributes:s})=>(0,y.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{o.push(e)},onKeyDown:h,onClick:l,...s,className:(0,r.A)("tabs__item",b.tabItem,s?.className,{"tabs__item--active":n===e}),children:t??e},e))})}function j({lazy:e,children:t,selectedValue:n}){const i=(Array.isArray(t)?t:[t]).filter(Boolean);if(e){const e=i.find(e=>e.props.value===n);return e?(0,s.cloneElement)(e,{className:(0,r.A)("margin-top--md",e.props.className)}):null}return(0,y.jsx)("div",{className:"margin-top--md",children:i.map((e,t)=>(0,s.cloneElement)(e,{key:t,hidden:e.props.value!==n}))})}function v(e){const t=g(e);return(0,y.jsxs)("div",{className:(0,r.A)(i.G.tabs.container,"tabs-container",b.tabList),
1children:[(0,y.jsx)(w,{...t,...e}),(0,y.jsx)(j,{...t,...e})]})}function I(e){const t=(0,x.A)();return(0,y.jsx)(v,{...e,children:u(e.children)},String(t))}},1588:(e,t,n)=>{n.d(t,{A:()=>s});const s=n.p+"assets/images/fruit-search-app-b9503dddbcb5f2626cc84003e6a96e37.webp"},1671:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>h,default:()=>p,frontMatter:()=>l,metadata:()=>s,toc:()=>u});const s=JSON.parse('{"id":"path/react/fruit-search-app/README","title":"Fruit Search App","description":"Written on February 19, 2026","source":"@site/docs/02-path/react/fruit-search-app/README.mdx","sourceDirName":"02-path/react/fruit-search-app","slug":"/path/react/fruit-search-app/","permalink":"/docs/path/react/fruit-search-app/","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":7,"frontMatter":{"sidebar_position":7,"sidebar_label":"Fruit Search App \u2605","title":"Fruit Search App"},"sidebar":"tutorialSidebar","previous":{"title":"Color Picker App","permalink":"/docs/path/react/color-picker-app/"},"next":{"title":"One-Time Password Generator","permalink":"/docs/path/react/one-time-password-generator/"}}');var r=n(4848),i=n(8453),a=n(1470),o=n(9365),c=n(8774);const l={sidebar_position:7,sidebar_label:"Fruit Search App \u2605",title:"Fruit Search App"},h="Fruit Search App",d={},u=[{value:"The Project",id:"the-project",level:2},{value:"Source Code",id:"source-code",level:2},{value:"React, 1984, and the Problem with AI",id:"react-1984-and-the-problem-with-ai",level:2},{value:"useEffect: Synchronization, Not Reaction",id:"useeffect-synchronization-not-reaction",level:2},{value:"Batching vs Debouncing: Two Cousins That Look Alike",id:"batching-vs-debouncing-two-cousins-that-look-alike",level:2},{value:"useRef: The Director of Attention",id:"useref-the-director-of-attention",level:2},{value:"Custom Hooks: Separating Logic from Component",id:"custom-hooks-separating-logic-from-component",level:2},{value:"async/await: A Discovery in the Review",id:"asyncawait-a-discovery-in-the-review",level:2},{value:"The Transparency of This Log",id:"the-transparency-of-this-log",level:2},{value:"What I Learned",id:"what-i-learned",level:2}];function m(e){const t={br:"br",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{className:"article-meta",children:(0,r.jsx)("time",{dateTime:"2026-02-19",children:"Written on February 19, 2026"})}),"\n",(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"fruit-search-app",children:"Fruit Search App"})}),"\n",(0,r.jsx)("img",{src:n(1588).A,alt:"Fruit Search App Preview - Search results for 'app' showing Apple, Apricot and Grapefruit",loading:"lazy",decoding:"async",width:"1904",height:"946",style:{width:"100%",height:"auto",maxWidth:"550px",borderRadius:"16px"}}),"\n",(0,r.jsx)(t.h2,{id:"the-project",children:"The Project"}),"\n",(0,r.jsxs)(t.p,{children:["A freeCodeCamp workshop that concluded the ",(0,r.jsx)(t.strong,{children:'"Understanding Effects and Referencing Values in React"'})," section, putting ",(0,r.jsx)(t.code,{children:"useEffect"}),", ",(0,r.jsx)(t.code,{children:"useRef"}),", and Custom Hooks into practice through asynchronous management with ",(0,r.jsx)(t.code,{children:"async/await"}),". Technically more complex than previous React projects, but above all rich in theoretical reflections that I struggled not to put in writing."]}),"\n",(0,r.jsx)(t.h2,{id:"source-code",children:"Source Code"}),"\n",(0,r.jsxs)(a.A,{children:[(0,r.jsx)(o.A,{value:"js",label:"index.jsx",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-jsx",children:'const { useState, useEffect } = React;\n\nexport function FruitsSearch() {\n  const [query, setQuery] = useState(\'\');\n  const [results, setResults] = useState([]);\n\n  function handleSubmit(e) {\n    e.preventDefault();\n  }\n\n  useEffect(() => {\n    if (query.trim() === \'\') {\n      setResults([]);\n      return;\n    }\n    const timeoutId = setTimeout(async () =>
1 {\n      try {\n        const response = await fetch(`https://fruit-search.freecodecamp.rocks/api/fruits?q=${query}`);\n        const data = await response.json();\n        setResults(data.map(fruit => fruit.name));\n      } catch (error) {\n        console.error("Error fetching data:", error);\n      }\n    }, 700);\n    return () => clearTimeout(timeoutId);\n  }, [query]);\n\n  return (\n    <div id="search-container">\n      <form onSubmit={handleSubmit}>\n        <label htmlFor="search-input">Search for fruits:</label>\n        <input\n          id="search-input"\n          type="search"\n          value={query}\n          onChange={(e) => setQuery(e.target.value)}\n        />\n      </form>\n      <div id="results">\n        {results.length > 0 ? (\n          results.map(item => (\n            <p key={item} className="result-item">{item}</p>\n          ))\n        ) : (\n          <p>No results found</p>\n        )}\n      </div>\n    </div>\n  );\n};\n'})})}),(0,r.jsx)(o.A,{value:"html",label:"index.html",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-html",children:'<!DOCTYPE html>\n<html>\n<head>\n  <meta charset="UTF-8" />\n  <title>Fruits Search</title>\n   <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"><\/script>\n   <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"><\/script>\n   <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"><\/script>\n  <script \n    data-plugins="transform-modules-umd"\n    type="text/babel"\n    src="index.jsx"\n  ><\/script>\n  <link rel="stylesheet" href="styles.css" />\n</head>\n<body>\n  <div id="root"></div>\n  <script\n    data-plugins="transform-modules-umd"\n    type="text/babel"\n    data-presets="react"\n    data-type="module"\n  >\n    import { FruitsSearch } from \'./index.jsx\';\n    ReactDOM.createRoot(document.getElementById(\'root\')).render(<FruitsSearch />);\n  <\/script>\n</body>\n</html>\n'})})}),(0,r.jsx)(o.A,{value:"css",label:"styles.css",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-css",children:"body {\n  font-family: Arial, sans-serif;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  height: 100vh;\n  background-color: #f4f4f4;\n}\n\n#search-container {\n  text-align: center;\n  background: white;\n  padding: 20px;\n  border-radius: 10px;\n  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n}\n\n#search-input {\n  padding: 10px;\n  width: 80%;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  margin-bottom: 10px;\n}\n\n#results {\n  text-align: left;\n  max-height: 150px;\n  overflow-y: auto;\n}\n.result-item {\n  padding: 5px;\n  border-bottom: 1px solid #ddd;\n}\n"})})})]}),"\n",(0,r.jsx)(t.h2,{id:"react-1984-and-the-problem-with-ai",children:"React, 1984, and the Problem with AI"}),"\n",(0,r.jsxs)(t.p,{children:["Ever since I discovered what's under the hood of ",(0,r.jsx)(t.code,{children:"useRef"}),", essentially a ",(0,r.jsx)(t.code,{children:"{ current: value }"})," object that React manages in memory, exactly as plain JavaScript would do, I found myself asking the same question I ask with every React project: ",(0,r.jsx)(t.em,{children:"how useful will all this be in a future where AI writes most of the code?"}),(0,r.jsx)(t.br,{}),"\n","The reflection got deeper. It's true that AI will write less code with this library, but it still has to remember (keep in the context window) that for each of React's functions there are, in fact, JavaScript functions with behaviors that aren't directly visible. It's as if we're adding a layer of invisible complexity that AI still needs to know to do debugging."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Newspeak from 1984"})," came to mind: a vocabulary ideally reduced from 50,000 to 5,000 words to limit thought. Isn't React the same thing? It reduces available functions, groups behaviors under new names. A writer who only knows those 5,000 words, isn't he missing the possibility of combining the remaining 45,000 in ways that weren't even conceivable with the reduced vocabulary? Aren't we therefore depriving an AI even more capable than today's of the possibility of combining raw, uncontained functions to create the perfect system for the application being designed? Are we adding unnecessary complexity?"]}),"\n",(0,r.jsxs)(t.p,{children:["I realize I can't study React without asking myself these kinds of questions. In these moments, I find comfort in the fact that React is not a framework but a library: nothing prevents me from mixing both. But the question remained.",(0,r.jsx)(t.br,{}),"\n","I looked for answers that would disprove this thought, because I was aware of the ",(0,r.jsx)(t.strong,{children:"Dunning-Kruger effect"})," I felt on me, after all, this is only the 7th React exercise I've done. The Code Tutor answered with five points that convinced me:"]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"1. The inverted metaphor."})," In 1984, Newspeak reduces words to ",(0,r.jsx)(t.em,{children:"reduce"})," the ability to think. In React, imperative commands are reduced to ",(0,r.jsx)(t.em,{children:"increase"})," the ability to manage complexity. With Vanilla JS you have control over every single atom, but if you need to manage 10 million atoms, the probability of unmanageable spaghetti code is extremely high, even for an AI. React doesn't remove words to censor you, it removes them to prevent the building from collapsing under the weight of useless details."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"2. AI loves structures, not chaos."})," If you have a ",(0,r.jsx)(t.code,{children:"count"})," variable displayed in 10 places on the page, in Vanilla JS an AI has to remember to write 10 ",(0,r.jsx)(t.code,{children:"document.getElementById"}),' instructions every time it changes. If it forgets one (and AIs "hallucinate" or lose context), the UI is silently broken. In React, the AI writes ',(0,r.jsx)(t.code,{children:"count"})," in state and the engine takes care of the rest. React provides AI with a proven mental structure to solve the synchronization problem, which is mathematically difficult."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"3. The Law of Leaky Abstractions."})," Joel Spolsky (the inventor of Trello) wrote: ",(0,r.jsx)(t.em,{children:'"All non-trivial abstractions, to some degree, are leaky."'})," React is an abstraction over pure JS. As long as everything goes well, the 5,000 words are enough. But as soon as there's a weird browser bug, a performance issue, or a complex 60fps animation, React's Newspeak fails. And if you don't know pure JS, you don't know how to fix the leak."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"4. The Human-AI collaboration factor."})," AI will write the code, but who will read it? If it spits out 5,000 lines of ultra-optimized but incomprehe
1nsible Vanilla JS and I need to change the color of a button, I'm screwed. React is the ",(0,r.jsx)(t.em,{children:"lingua franca"})," between human intent and machine execution. It's the common language that allows a human being to intervene on what the AI has produced."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"5. The Sapir-Whorf Hypothesis."})," ",(0,r.jsx)(t.em,{children:'"The language you speak shapes the way you think."'})," In programming this is a recognized fact: if you only know React's Newspeak, your brain will try to solve any problem with ",(0,r.jsx)(t.code,{children:"useState"})," and a component, even when it's not needed. Knowing the 50,000 words reminds you that sometimes two lines of JS and a standard HTML tag are enough to do what React would do with 100 lines of complex code."]}),"\n",(0,r.jsx)(t.p,{children:'He then added a reflection that definitively closed the circle: in 1984, the Party reduced words to prevent "thoughtcrime", if the word "freedom" doesn\'t exist, you can\'t even formulate the thought of rebelling. React did the same thing with code: it made it physically difficult to write certain buggy patterns (direct DOM manipulation, unsynchronized state, listeners lost in memory). It removed the vocabulary of imperative DOM to force you to think in terms of State.'}),"\n",(0,r.jsx)(t.h2,{id:"useeffect-synchronization-not-reaction",children:"useEffect: Synchronization, Not Reaction"}),"\n",(0,r.jsxs)(t.p,{children:["The tutor immediately warned me that ",(0,r.jsxs)(t.strong,{children:["I shouldn't see ",(0,r.jsx)(t.code,{children:"useEffect"}),' as a way to say "do this when this happens".']}),(0,r.jsx)(t.br,{}),"\n","The correct way is ",(0,r.jsx)(t.strong,{children:"Synchronization"}),". I shouldn't think: ",(0,r.jsx)(t.em,{children:'"When I click, start the timer."'})," Rather: ",(0,r.jsxs)(t.em,{children:['"I want the timer to be synchronized with the ',(0,r.jsx)(t.code,{children:"isActive"})," state. If it's active, the timer should start. If it's not active, it should stop.\""]}),(0,r.jsx)(t.br,{}),"\n",(0,r.jsx)(t.code,{children:"useEffect"})," therefore acts as a mechanism that keeps the component synchronized with external systems (Browser, API, time) that React doesn't directly control."]}),"\n",(0,r.jsxs)(t.p,{children:["This completely changes how you reason about architecture, because if I think in events, my code becomes a list of instructions: ",(0,r.jsx)(t.em,{children:'"When I click Start, start the timer. When I click Stop, stop it. When I click Reset, reset everything."'}),' It works as long as things are simple. But if I add a new condition, like "the timer should also stop if the user leaves the page," I have to remember to go add that logic in every right place. If I forget a handler, the bug is guaranteed.',(0,r.jsx)(t.br,{}),"\n","If instead I think in synchronization, I ask myself just one question: ",(0,r.jsxs)(t.em,{children:['"When should the timer be active? In this case when ',(0,r.jsx)(t.code,{children:"isActive"})," is ",(0,r.jsx)(t.code,{children:"true"}),'. Period."']})," I write a single ",(0,r.jsx)(t.code,{children:"useEffect"})," that observes ",(0,r.jsx)(t.code,{children:"isActive"})," and behaves accordingly. If tomorrow I add a new way to stop the timer, a timeout, leaving the page, a network error, I don't have to touch the ",(0,r.jsx)(t.code,{children:"useEffect"}),". I just need to set ",(0,r.jsx)(t.code,{children:"isActive = false"})," from anywhere in the code, and the timer stops on its own. The logic is in one place, not distributed across ten handlers."]}),"\n",(0,r.jsx)(t.h2,{id:"batching-vs-debouncing-two-cousins-that-look-alike",children:"Batching vs Debouncing: Two Cousins That Look Alike"}),"\n",(0,r.jsxs)(t.p,{children:["freeCodeCamp talked about Debouncing, yet it seemed like I was seeing the Batching from the ",(0,r.jsx)(c.A,{to:"/docs/path/react/toggle-text-app",children:"Toggle Text App"})," again. Weren't they the same thing?"]}),"\n",(0,r.jsx)(t.p,{children:'The answer I received was that they are two mechanisms that both "wait," but with completely different purposes:'}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{}),(0,r.jsx)(t.th,{children:(0,r.jsx)(t.strong,{children:"Batching"})}),(0,r.jsx)(t.th,{children:(0,r.jsx)(t.strong,{children:"Debouncing"})})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Who does it?"})}),(0,r.jsx)(t.td,{children:"React automatically"}),(0,r.jsx)(t.td,{children:"You, in the code"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Purpose"})}),(0,r.jsx)(t.td,{children:"Merge multiple renders into one"}),(0,r.jsx)(t.td,{children:"Delay a heavy call"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Analogy"})}),(0,r.jsx)(t.td,{children:"The waiter who waits for all orders before going to the kitchen"}),(0,r.jsx)(t.td,{children:"The elevator doors that restart the timer every time someone enters"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"When does it trigger?"})}),(0,r.jsxs)(t.td,{children:["Every time you call multiple ",(0,r.jsx)(t.code,{children:"setState"})," in a row"]}
1),(0,r.jsx)(t.td,{children:'Only after X milliseconds of "silence"'})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Typical use case"})}),(0,r.jsx)(t.td,{children:"Automatic render optimization"}),(0,r.jsx)(t.td,{children:"Search input, resize, scroll"})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"In this workshop I used precisely Debouncing: I wait 700ms after the last keystroke before calling the API, avoiding a request for every single character typed."}),"\n",(0,r.jsx)(t.h2,{id:"useref-the-director-of-attention",children:"useRef: The Director of Attention"}),"\n",(0,r.jsxs)(t.p,{children:["freeCodeCamp introduced me to ",(0,r.jsx)(t.code,{children:"useRef"})," with an example on input focus. The first thing I thought was: ",(0,r.jsx)(t.em,{children:"complexity added to what HTML and CSS already did perfectly well on their own."})," I actually understood why later.",(0,r.jsx)(t.br,{}),"\n",(0,r.jsx)(t.code,{children:"useRef"})," and ",(0,r.jsx)(t.code,{children:"useState"})," solve two different problems. ",(0,r.jsx)(t.code,{children:"useState"})," is a shop window, so every time you change something, React redraws everything and the user sees it. ",(0,r.jsx)(t.code,{children:"useRef"})," is the pocket: you can put things in it, take them out, change them, and nobody notices. No re-render.",(0,r.jsx)(t.br,{}),"\n","The ",(0,r.jsx)(t.code,{children:"inputRef.current"})," syntax exists because ",(0,r.jsx)(t.code,{children:"useRef"})," creates a ",(0,r.jsx)(t.code,{children:"{ current: value }"})," object that survives re-renders. Normal variables inside a component die and are reborn with every redraw. ",(0,r.jsx)(t.code,{children:"useRef"})," doesn't, React always returns you the exact same memory address."]}),"\n",(0,r.jsxs)(t.p,{children:["But the use case that struck me most is accessibility. In Single Page Applications the page never reloads: the ",(0,r.jsx)(t.code,{children:"index.html"})," is always the same. For those using a keyboard or screen reader, this is problematic because without the browser thinking for you to notify the user of the page change, ",(0,r.jsx)(t.strong,{children:"you"})," have to communicate to the browser itself that something has changed. Here are three extremely problematic scenarios if you don't manage focus with ",(0,r.jsx)(t.code,{children:"useRef"}),":"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Form Error:"}),' The user fills out a long form, clicks "Submit" at the bottom of the page. There\'s an error in the first field at the top: a red message appears. Visually it\'s obvious. But the browser focus stayed on the "Submit" button at the bottom. Someone using a screen reader hears: "Submit button pressed." Then silence... The error message exists in the DOM, but nobody communicated it to them. With ',(0,r.jsx)(t.code,{children:"useRef"}),", you move the focus directly to the error message the moment it appears: the screen reader reads it immediately."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Page Change:"})," In a traditional HTML site, when you click a link the page reloads and focus automatically restarts from the beginning. In React this doesn't happen: the content changes, but focus remains on the link you just clicked, which sometimes doesn't even exist in the DOM anymore because the component was unmounted. The screen reader finds itself announcing a ghost element. With ",(0,r.jsx)(t.code,{children:"useRef"}),', when the "page" changes you move focus to the ',(0,r.jsx)(t.code,{children:"<h1>"})," of the new content: the user immediately knows where they are."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Modal Opening"})," (dialog window that appears over the page)",(0,r.jsx)(t.strong,{children:":"})," Visually the background is dark, the rest of the site is inaccessible. For the keyboard, no: everything still exists. If the user presses TAB enough times, focus escapes the modal and ends up on links and buttons hidden under the dark background. They're interacting with something they can't see. With ",(0,r.jsx)(t.code,{children:"useRef"}),', when the modal opens you move focus inside it (usually to the first input or the "Close" button), thus allowing only actions within it.']}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.strong,{children:"Curb Cut Effect"})," always applies, which I first encountered in the Google UX course: the solution designed for a specific need ends up helping everyone. Managing focus with ",(0,r.jsx)(t.code,{children:"useRef"})," helps power users who don't touch the mouse, situational users with a broken arm or dead trackpad, and, something I'd never considered until now, those browsing on Smart TV or PlayStation. A console controller works exactly like a keyboard: Up, Down, Right, Left, Enter. If focus is managed well, the site works on the couch too. If it's not, the cursor gets stuck (and the user leaves)."]}),"\n",(0,r.jsx)(t.h2,{id:"custom-hooks-separating-logic-from-component",children:"Custom Hooks: Separating Logic from Component"}),"\n",(0,r.jsxs)(t.p,{children:["I wondered where to put the accessibility code: did it make sense to include it directly in the component? I discovered that common practice is to extract it into an external function, a Custom Hook, that lives in its dedicated file, for example ",(0,r.jsx)(t.code,{children:"hooks/useFocus.js"}),", and is called with a single line. The component stays clean, the logic is in one place and reusable wherever I need it."]}),"\n",(0,r.jsx)(t.h2,{id:"asyncawait-a-discovery-in-the-review",children:"async/await: A Discovery in the Review"}),"\n",(0,r.jsxs)(t.p,{children:["The Vademecum was essential for reviewing ",(0,r.jsx)(t.code,{children:"try"}),", ",(0,r.jsx)(t.code,{children:"catch"}),", ",(0,r.jsx)(t.code,{children:"async"}),", and ",(0,r.jsx)(t.code,{children:"await"}),", because I didn't remember the syntax by heart. Rereading it, though, I discovered something that wasn't explained sufficiently: I thought ",(0,r.jsx)(t.code,{children:"async"})," and ",(0,r.jsx)(t.code,{children:"await"})," were inseparable. They're not.",(0,r.jsx)(t.br,{}),"\n","You can have an ",(0,r.jsx)(t.code,{children:"async"})," function without ",(0,r.jsx)(t.code,{children:"await"}),": it's syntactically valid, but pointlessly asynchronous. Conversely, ",(0,r.jsx)(t.code,{children:"await"})," can never appear outside an ",(0,r.jsx)(t.code,{children:"async"})," function: it's a syntax error. The two aren't inseparable, but they have a precise direction: ",(0,r.jsx)(t.code,{children:"await"})," needs ",(0,r.jsx)(t.code,{children:"async"}),", ",(0,r.jsx)(t.code,{children:"async"})," doesn't need ",(0,r.jsx)(t.code,{children:"await"}),".",(0,r.jsx)(t.br,{}),"\n","I immediately updated the Vademecum to reflect this distinction more precisely."]}),"\n",(0,r.jsx)(t.h2,{id:"the-transparency-of-this-log",children:"The Transparency of This Log"}),"\n",(0,r.jsxs)(t.p,{children:["It often happens that the questions I ask myself, like the one about 1984, seem stupid to me after reading the answer. The temptation to show myself as perfect is there, I admit it. But projects like ",(0,r.jsx)(c.A,{to:"/docs/path/html-css/landing-page",children:"Landing Page"})," and ",(0,r.jsx)(c.A,{to:"/docs/featured/maintenance-ui-concept",children:"Maintenance"}),' made me hit rock bottom with errors, and those experiences raised my tolerance for "seeming ignorant" so high that by now transparency comes naturally to me.']}),"\n",(0,r.jsxs)(t.p,{children:["I take notes on the questions and answers from the Code Tutor in a file called ",(0,r.jsx)(t.strong,{children:'"future README"'}),", then I try to organize them like I'm doing now. I'm finding it increasingly difficult to understand whether this site is a diary, a portfolio, or a second brain. Probably all three things together."]}),"\n",(0,r.jsx)(t.h2,{id:"what-i-learned",children:"What I Learned"}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"useEffect as Synchronization:"}),(0,r.jsx)(t.br,{}),"\n",'The most important mental model shift of the module. Not "do X when Y happens," but "keep this component synchronized with this external system." It completely changes how you design architecture.']}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Debouncing Implemented:"}),(0,r.jsx)(t.br,{}),"\n","700ms delay before calling the API. Every new keystroke cancels the previous timeout (",(0,r.jsx)(t.code,{children:"clearTimeout"}),") and starts a new one. The cleanup function of ",(0,r.jsx)(t.code,{children:"useEffect"})," (",(0,r.jsx)(t.code,{children:"return () => clearTimeout(timeoutId)"}),") is the mechanism that makes all this possible."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"useRef as Re-render Survival:"}),(0,r.jsx)(t.br,{}),"\n","A reference to a ",(0,r.jsx)(t.code,{children:"{ current: value }"})," object that React keeps in memory between renders. It doesn't trigger re-renders when it changes: it's the difference between the shop window (visible to everyone) and the pocket (invisible, but always accessible)."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Custom Hooks as Logic Separation:"}),(0,r.jsx)(t.br,{}),"\n","Extracting logic into a reusable hook (",(0,r.jsx)(t.code,{children:"hooks/useFocus.js"}),") keeps components clean and centralizes cross-cutting behaviors like accessibility."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"async/await Are Not Inseparable:"}),(0,r.jsx)(t.br,{}),"\n",(0,r.jsx)(t.code,{children:"async"})," declares a function as asynchronous. ",(0,r.jsx)(t.code,{children:"await"})," suspends execution inside that function. They can exist without each other, even if it rarely makes sense."]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.strong,{children:"Next:"}),(0,r.jsx)(t.br,{}),"\n","One-Time Password Generator (Lab)"]})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(m,{...e})}):m(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>o});var s=n(6540);const r={},i=s.createContext(r);function a(e){const t=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),s.createElement(i.Provider,{value:t},e.children)}},9365:(e,t,n)=>{n.d(t,{A:()=>a});
1n(6540);var s=n(4164);const r={tabItem:"tabItem_Ymn6"};var i=n(4848);function a({children:e,hidden:t,className:n}){return(0,i.jsx)("div",{role:"tabpanel",className:(0,s.A)(r.tabItem,n),hidden:t,children:e})}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.