<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hugo Naili</title>
    <description>The latest articles on DEV Community by Hugo Naili (@hugonaili).</description>
    <link>https://dev.to/hugonaili</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1489795%2F79f11da5-b603-4088-8769-bfda42e813a7.jpg</url>
      <title>DEV Community: Hugo Naili</title>
      <link>https://dev.to/hugonaili</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hugonaili"/>
    <language>en</language>
    <item>
      <title>Building search for a smart TV streaming platform</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Mon, 03 Aug 2026 21:26:08 +0000</pubDate>
      <link>https://dev.to/hugonaili/building-search-for-a-smart-tv-streaming-platform-27fg</link>
      <guid>https://dev.to/hugonaili/building-search-for-a-smart-tv-streaming-platform-27fg</guid>
      <description>&lt;p&gt;Search on a streaming platform looks simple from the couch. You type a few letters, results appear, you press OK. The interaction most people compare it to is Netflix or YouTube, and the comparison is fair — that is the bar.&lt;/p&gt;

&lt;p&gt;What sits behind it is a fan-out. A single keyword goes to several content APIs at once, each returning a different kind of thing, and the interface has to resolve those responses into one ordered list that makes sense to someone holding a remote. That resolution is where the work is.&lt;/p&gt;

&lt;p&gt;I built the search experience for a streaming platform on smart TVs using &lt;a href="https://lightningjs.io/" rel="noopener noreferrer"&gt;LightningJS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One query, many sources
&lt;/h2&gt;

&lt;p&gt;A streaming catalog is not one index. Movies, series, live channels, networks, and people each live behind their own endpoint, with their own response shape, their own latency profile, and their own idea of what a relevance score means.&lt;/p&gt;

&lt;p&gt;So a keyword becomes N concurrent requests. That immediately raises questions the DOM and a single search endpoint would have answered for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When do you render?&lt;/strong&gt; Waiting for all responses means the slowest endpoint sets your perceived latency. Rendering as each arrives means the list reorders under the user while they are looking at it — and on a TV, where the user tracks a focus highlight rather than a cursor, a list that reorders mid-look is disorienting in a way it isn't on a phone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you order across sources?&lt;/strong&gt; Each endpoint returns its own ranking, and those rankings are not comparable. An exact title match from the movies endpoint and a fuzzy match from the people endpoint both come back as "the top result." Merging them requires a ranking policy that lives in the client, because no single backend has the whole picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when one fails?&lt;/strong&gt; Partial failure is the normal case, not the exception. If the live-channels endpoint times out, the user should still get movies — but they should not silently get a result set that is missing a category they were looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why ordering is worse on a TV
&lt;/h2&gt;

&lt;p&gt;On the web, a reordering result list is mildly annoying. On a TV it breaks the interaction.&lt;/p&gt;

&lt;p&gt;The user is not pointing at anything. They are moving a highlight with a D-pad, and their model of the screen is positional — the thing they want is two to the right. If a slow endpoint returns and inserts three results ahead of the highlighted item, the highlight is now on something else, and the user has to re-read the row to work out where they are. Do that twice and they stop trusting the screen.&lt;/p&gt;

&lt;p&gt;Every mitigation costs something. Lock ordering after first paint and you lose relevance when a better result arrives late. Append late results to the end regardless of score and you get stability at the price of correctness. Hold the highlight on its item as the list reflows and you preserve the user's position but shift the layout under a stationary cursor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input constraint shapes everything upstream
&lt;/h2&gt;

&lt;p&gt;The user is typing with a directional pad on an on-screen keyboard. Each character is a cursor traversal plus an OK press. Nobody types a full title.&lt;/p&gt;

&lt;p&gt;So the fan-out fires on two- and three-character prefixes, which means every endpoint is being asked its least selective question, which means result sets are large and the ranking problem is at its hardest exactly when you have the least information to solve it. Longer queries would be easier in every respect and you will almost never get one.&lt;/p&gt;

&lt;p&gt;Request volume follows from this. A naive implementation fires N requests per keystroke, and a user pecking out six characters generates 6N, most superseded before they return. Debouncing is not optional, and the usual approach does not transfer cleanly: D-pad input is slow and irregular, with long pauses while the cursor travels between distant keys and then bursts on adjacent ones. A fixed timeout tuned for typing behaves badly in both directions — too eager during the pauses, too sluggish during the bursts.&lt;/p&gt;

&lt;p&gt;Out-of-order responses are a related problem worth calling out separately. Slow irregular input plus multiple endpoints plus living-room network conditions means a response for "do" can land after a response for "doc." Each of the N streams needs its own staleness check, not just a global one.&lt;/p&gt;

&lt;h2&gt;
  
  
  LightningJS and what it takes away
&lt;/h2&gt;

&lt;p&gt;LightningJS renders to a WebGL canvas rather than the DOM. On TV hardware that is the difference between a smooth app and a stuttering one — DOM-based TV apps degrade badly on the older devices that make up much of the installed base, and stutter is unmissable on a ten-foot screen.&lt;/p&gt;

&lt;p&gt;The cost is that the browser stops helping. No reflow, no CSS layout, no native text input, no focus management. Every element is a texture at a coordinate you set.&lt;/p&gt;

&lt;p&gt;Focus becomes an explicit system: a tree you maintain, key handlers you write for every direction, and no default behavior when you miss a case. Search is harder than most screens in this respect because it has several focusable regions the user moves between constantly — on-screen keyboard, query field, results grid, category filters — and every transition between them is code you write. The failure mode is a press that does nothing, which reads to a user as the app being broken rather than as a missing handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Texture memory
&lt;/h2&gt;

&lt;p&gt;Every result tile carries a poster, and every poster is a WebGL texture resident in GPU memory. A grid of thirty tiles is thirty textures; scrolling adds more.&lt;/p&gt;

&lt;p&gt;Lightning provides texture management primitives but the retention policy is yours. Too aggressive and users see pop-in as posters reload on scroll-back. Too lax and you crash on the low end of the device matrix — and the low end of a TV device matrix is genuinely low.&lt;/p&gt;

&lt;p&gt;Fan-out sharpens this. Multiple content types means multiple poster aspect ratios and sizes arriving together, so the memory cost of a result set varies with what the query happened to match.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part: a ranking policy the backends couldn't give me
&lt;/h2&gt;

&lt;p&gt;The endpoints could each tell me what was most relevant within their own catalog. None of them could tell me whether a movie beat a person, because none of them could see the other's results. That judgment had to live in the client, and it had to be made on two or three characters of input.&lt;/p&gt;

&lt;p&gt;What I settled on was deliberately simple. Exact title match first, regardless of source. Then movies and series. People always last.&lt;/p&gt;

&lt;p&gt;The reasoning behind the first rule is that on a short prefix, an exact match is the only high-confidence signal available. If someone types "up" and there is a film called Up, the probability that they meant something else is low enough to ignore. Everything after that is inference; an exact match is not, so it goes above the inference.&lt;/p&gt;

&lt;p&gt;The second rule follows from intent. On a streaming app the user is looking for something to watch. Movies and series are the destination; everything else is a route to them. Ordering by content type rather than by score is technically a worse use of the relevance information available, and it is the right call anyway, because the relevance information is weakest precisely when the ordering matters most.&lt;/p&gt;

&lt;p&gt;The third rule is the one I deliberately got wrong. People are demoted even when the match is exact — someone typing an actor's name in full still sees that actor's films before the actor. That is incorrect for the user who specifically wanted the person page, and they pay for it by traveling further with the D-pad. I accepted that cost because the failure is recoverable in a few presses, whereas the alternative failure is not: if a person card can take position one, then a user searching for something to watch lands on a card that plays nothing, and the fix is to back out and start over. Asymmetric costs justify an asymmetric policy.&lt;/p&gt;

&lt;p&gt;Render timing worked the same way — pick a cheap failure over an expensive one. Results paint progressively as each endpoint returns, so first paint is fast and the screen never sits empty waiting on the slowest source. But ordering locks at 400ms. After that, late arrivals append in place rather than sorting into position.&lt;/p&gt;

&lt;p&gt;Four hundred milliseconds is roughly where a screen change stops reading as "still loading" and starts reading as "the thing moved." Before that threshold the user is still absorbing the screen and reordering is invisible. After it, they have oriented, and moving their highlight is a betrayal of a model they have already built.&lt;/p&gt;

&lt;p&gt;The cost is real and I knew it going in: an endpoint returning at 600ms with a genuinely better match gets appended below results that deserve it less. I would rather serve a slightly worse ordering that stays still than a better one that moves. On a device where the only pointer is a highlight the user is steering blind, stability is a correctness property, not a polish item.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>performance</category>
    </item>
    <item>
      <title>Structured data in Next.js: Person and BlogPosting schema</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Mon, 03 Aug 2026 21:25:32 +0000</pubDate>
      <link>https://dev.to/hugonaili/structured-data-in-nextjs-person-and-blogposting-schema-4nml</link>
      <guid>https://dev.to/hugonaili/structured-data-in-nextjs-person-and-blogposting-schema-4nml</guid>
      <description>&lt;p&gt;Most Next.js sites ship with good metadata and no structured data. Title tags, Open Graph, canonical URLs — all correct. And then nothing that tells a search engine &lt;em&gt;what kind of thing&lt;/em&gt; the page is or &lt;em&gt;who made it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That gap matters more than it used to. Structured data is how a search engine moves from "this page contains the string Hugo Naili" to "this page is authored by an entity named Hugo Naili who also has these profiles and works here." The second is a fact about the world. The first is a substring match.&lt;/p&gt;

&lt;p&gt;This is a practical walkthrough: what to add, where it goes in the App Router, and the mistakes that make it silently useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  What JSON-LD actually is
&lt;/h2&gt;

&lt;p&gt;A block of JSON in a &lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;&lt;/code&gt; tag describing the page in Schema.org vocabulary. It is not rendered, does not affect layout, and adds a negligible amount to your bundle.&lt;/p&gt;

&lt;p&gt;Three properties carry most of the weight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@type&lt;/code&gt;&lt;/strong&gt; — what kind of thing this is. &lt;code&gt;Person&lt;/code&gt;, &lt;code&gt;BlogPosting&lt;/code&gt;, &lt;code&gt;Organization&lt;/code&gt;, &lt;code&gt;WebSite&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@id&lt;/code&gt;&lt;/strong&gt; — a stable, unique URI for the entity. Underused and important; more below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sameAs&lt;/code&gt;&lt;/strong&gt; — an array of URLs where the same entity appears elsewhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;sameAs&lt;/code&gt; is the one people skip and shouldn't. It is how you assert that the GitHub account, the dev.to profile, and the personal site are the same person rather than three coincidences. Entity consolidation is the whole game for personal sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Person schema, in the root layout
&lt;/h2&gt;

&lt;p&gt;This belongs on every page, so it goes in &lt;code&gt;app/layout.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hugonaili.com/#person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hugo Naili&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hugonaili.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;jobTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Senior Demo Engineer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;worksFor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Organization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Contentful&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.contentful.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Senior software engineer with over ten years of experience building React and Next.js systems, design systems, and technical demo environments.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;knowsAbout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Frontend architecture&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Design systems&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GraphQL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;sameAs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://github.com/hugonaili&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dev.to/hugonaili&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://gitlab.com/hugonaili&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://medium.com/@HugoNaili&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;
          &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two notes on this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;@id&lt;/code&gt; is doing real work.&lt;/strong&gt; &lt;code&gt;https://hugonaili.com/#person&lt;/code&gt; is a stable identifier for you as an entity. Every article you publish can reference that exact string as its author, and a parser resolves all of them to one entity rather than treating each article's author as a separate unnamed person. Without it, you have N disconnected author objects that happen to share a name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;knowsAbout&lt;/code&gt; is not decorative.&lt;/strong&gt; It is a topical association between an entity and subject areas, and it costs nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  BlogPosting schema, per article
&lt;/h2&gt;

&lt;p&gt;Make it a component so every post gets consistent output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// components/BlogPostSchema.tsx&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BlogPostSchemaProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;   &lt;span class="c1"&gt;// ISO 8601: '2026-08-03'&lt;/span&gt;
  &lt;span class="nx"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPostSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;BlogPostSchemaProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://hugonaili.com/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BlogPosting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;datePublished&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dateModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedAt&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hugonaili.com/#person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hugonaili.com/#person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;mainEntityOfPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebPage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;inLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;
      &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note &lt;code&gt;author&lt;/code&gt; and &lt;code&gt;publisher&lt;/code&gt; are references — &lt;code&gt;{ '@id': ... }&lt;/code&gt; — not inline objects. This is the payoff from defining &lt;code&gt;@id&lt;/code&gt; in the layout. The parser follows the reference to the full Person definition. One canonical description, referenced everywhere.&lt;/p&gt;

&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/blog/[slug]/page.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;BlogPostSchema&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/BlogPostSchema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlogPostSchema&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatedAt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://hugonaili.com/images/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Breadcrumbs, which are cheap and visible
&lt;/h2&gt;

&lt;p&gt;BreadcrumbList changes what your URL looks like in results — &lt;code&gt;hugonaili.com › blog › article-title&lt;/code&gt; instead of a raw path. Small change, measurable click-through effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;breadcrumbSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BreadcrumbList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;itemListElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ListItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hugonaili.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ListItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hugonaili.com/blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ListItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Emit it alongside the BlogPosting. Multiple JSON-LD blocks on one page are fine and normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes that make this silently useless
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Canonical says one thing, page content says another.&lt;/strong&gt; If your canonical points to your own domain but the article footer links to another copy labeled "read the original here," you have contradicted yourself. Schema is a claim about authority; anything on the page that undercuts the claim undercuts the schema. This applies doubly to cross-posted content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assets hosted on the platform you cross-posted to.&lt;/strong&gt; Your schema asserts you published the article. Every image loads from another platform's CDN. That's a signal in the opposite direction, and it's free to fix — download the images, serve them yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dates that aren't ISO 8601.&lt;/strong&gt; &lt;code&gt;'August 3, 2026'&lt;/code&gt; is not a date to a parser. &lt;code&gt;'2026-08-03'&lt;/code&gt; is. This fails silently; nothing warns you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;dateModified&lt;/code&gt; earlier than &lt;code&gt;datePublished&lt;/code&gt;.&lt;/strong&gt; Usually a bug where one field is hardcoded. It invalidates the whole block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Describing content that isn't on the page.&lt;/strong&gt; The schema must describe what a user actually sees. Headline mismatches, or an author who appears nowhere in the visible page, read as manipulation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing a visible byline.&lt;/strong&gt; If the schema names an author but the rendered page shows no author name, photo, or bio, you have a mismatch between what you're claiming and what the page demonstrates. Add the visible byline. It's a better page anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying it
&lt;/h2&gt;

&lt;p&gt;Google's Rich Results Test at &lt;code&gt;search.google.com/test/rich-results&lt;/code&gt; parses a live URL and shows you exactly what it extracted. Schema.org's validator is stricter about vocabulary correctness and worth running once per schema type.&lt;/p&gt;

&lt;p&gt;Both catch syntax errors. Neither catches the semantic problems above — a page can validate perfectly while contradicting itself in the body copy. Read the rendered page and ask whether a person would agree with what the JSON claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to expect
&lt;/h2&gt;

&lt;p&gt;Structured data is not a ranking factor in the direct sense. It doesn't move you up the page.&lt;/p&gt;

&lt;p&gt;What it does is make your pages &lt;em&gt;legible&lt;/em&gt; — parseable as entities with relationships rather than documents with keywords. That legibility is what enables enhanced snippets, breadcrumb display, and eventually entity recognition. It also increasingly determines whether AI-driven search surfaces describe you accurately, since those systems lean heavily on structured signals.&lt;/p&gt;

&lt;p&gt;The work is a couple of hours. The main cost of skipping it is that everything downstream that depends on a machine understanding who you are has to infer it from prose instead.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>seo</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Extracting design tokens from a site you don't control</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Mon, 03 Aug 2026 21:24:57 +0000</pubDate>
      <link>https://dev.to/hugonaili/extracting-design-tokens-from-a-site-you-dont-control-16b8</link>
      <guid>https://dev.to/hugonaili/extracting-design-tokens-from-a-site-you-dont-control-16b8</guid>
      <description>&lt;p&gt;The problem: given a URL, produce a design token set — colors, type scale, spacing rhythm, border radii, logo — good enough that a generic app re-skinned with those tokens reads as belonging to that brand.&lt;/p&gt;

&lt;p&gt;This sounds like a scraping problem. It is mostly not. Scraping gets you a pile of CSS values in about an hour. Turning that pile into a &lt;em&gt;usable token set&lt;/em&gt; is where the actual work is, and it took me several iterations to get right. Here is the approach that ended up working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the naive version fails
&lt;/h2&gt;

&lt;p&gt;The obvious first attempt: load the page, walk the DOM, collect every computed style, count frequencies, take the top values.&lt;/p&gt;

&lt;p&gt;I built this. It produces garbage, for a reason that is obvious in retrospect. Frequency counting is dominated by whatever element type is most numerous on the page, which is almost always body text and its containers. You get seven shades of near-black, &lt;code&gt;#ffffff&lt;/code&gt;, one grey, and a &lt;code&gt;16px&lt;/code&gt; font size. Technically accurate. Completely useless for making something look like the brand, because a brand's identity lives in its &lt;em&gt;accents&lt;/em&gt; — the button color, the display heading, the one saturated hue used sparingly — and accents are by definition rare.&lt;/p&gt;

&lt;p&gt;The fix is to weight by visual prominence rather than count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weighting by prominence
&lt;/h2&gt;

&lt;p&gt;Every element gets a prominence score before its styles are counted. The score I converged on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prominence = area_ratio × viewport_weight × role_weight
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;area_ratio&lt;/code&gt;&lt;/strong&gt; is the element's rendered area over the viewport area. A hero section outweighs a footer link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;viewport_weight&lt;/code&gt;&lt;/strong&gt; decays with distance below the fold. Something at scroll position zero counts fully; something 4000px down counts for very little. Brands front-load identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;role_weight&lt;/code&gt;&lt;/strong&gt; is a lookup by tag and semantic role. Buttons, links, headings, and elements with &lt;code&gt;role="button"&lt;/code&gt; get multiplied up substantially. This single term did more for output quality than anything else I tried, because it surfaces exactly the accent colors that frequency counting buries.&lt;/p&gt;

&lt;p&gt;With prominence weighting, a color used on three buttons above the fold outranks a grey used on four hundred spans, which is the correct answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Color: cluster, then assign roles
&lt;/h2&gt;

&lt;p&gt;Raw color extraction returns hundreds of near-identical values — anti-aliasing, opacity compositing, and hover states generate a smear around every intended color.&lt;/p&gt;

&lt;p&gt;Convert to a perceptually uniform space first. Clustering in sRGB gives you results that look wrong to a human eye because sRGB distance doesn't match perceived difference. OKLCH fixed this for me; LAB works too. Cluster with a distance threshold rather than a fixed k — you don't know in advance whether a brand has three colors or eleven.&lt;/p&gt;

&lt;p&gt;Then the harder part: assigning roles. A cluster set is not a token set. You need to know which one is &lt;code&gt;primary&lt;/code&gt;, which is &lt;code&gt;background&lt;/code&gt;, which is &lt;code&gt;text&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Heuristics that held up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Background&lt;/strong&gt; is the highest-area cluster, near-always. Very high confidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt; is the cluster with maximum contrast ratio against background, weighted toward clusters that appear on &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary&lt;/strong&gt; is the highest-chroma cluster that appears on an interactive element. Chroma is doing the heavy lifting — brands reserve saturation for the thing they want clicked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Surface&lt;/strong&gt; is a cluster within a small perceptual distance of background but not identical. Cards, panels, elevated regions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything left over goes into an unassigned pool. I do not try to force-assign; a wrong role assignment is worse than a missing one, because downstream code can fall back gracefully on a missing token but will render confidently wrong output on a mislabeled one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type scale: fit a ratio, don't collect sizes
&lt;/h2&gt;

&lt;p&gt;Collecting font sizes gives you a list like &lt;code&gt;[14, 16, 16, 18, 24, 32, 48]&lt;/code&gt;. You can use it directly, but the output is brittle — any size you need that isn't in the list has no principled value.&lt;/p&gt;

&lt;p&gt;Better: fit a modular scale. Take the prominence-weighted mode as the base (almost always the body size), then regress the remaining sizes against candidate ratios — 1.125, 1.2, 1.25, 1.333, 1.5, 1.618 — and pick the best fit by residual.&lt;/p&gt;

&lt;p&gt;Now instead of seven fixed numbers you have &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;ratio&lt;/code&gt;, and every step is derivable. When the demo needs a size the source site never used, you generate one that is consistent with the brand's rhythm rather than guessing.&lt;/p&gt;

&lt;p&gt;The same treatment works for spacing, though the fit is noisier because spacing is more often ad hoc. I extract a base unit — usually 4px or 8px, found as the GCD of common margin and padding values after discarding outliers — and express everything as multiples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Border radius is a personality variable
&lt;/h2&gt;

&lt;p&gt;Underrated signal. Collect radii from cards, buttons, and inputs, weighted by prominence, and reduce to a small set.&lt;/p&gt;

&lt;p&gt;What matters is not the exact pixel value but where the brand sits on the sharp-to-round axis, because that position implies other decisions. Fully-rounded pill buttons want more horizontal padding than square ones to look balanced. Sharp-cornered cards tolerate tighter gaps than heavily-rounded ones. I derive a &lt;code&gt;roundness&lt;/code&gt; scalar from the extracted radii and feed it into padding and gap calculations rather than treating radius as an isolated token.&lt;/p&gt;

&lt;p&gt;This is the difference between a re-skin that looks like the brand and one that looks like the brand's colors applied to someone else's layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logos: prefer declared, verify rendered
&lt;/h2&gt;

&lt;p&gt;Order of attempts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;link rel="icon"&amp;gt;&lt;/code&gt; and its variants, preferring SVG, then largest PNG.&lt;/li&gt;
&lt;li&gt;Open Graph and Twitter card images — often a logo lockup, sometimes a product shot, so this needs verification.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; or inline &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; inside &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, positioned in the first third horizontally. This is where a wordmark lives on the overwhelming majority of sites.&lt;/li&gt;
&lt;li&gt;Anything with &lt;code&gt;logo&lt;/code&gt; in a class, id, alt, or filename.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each candidate gets checked: reasonable aspect ratio (reject anything near-square and tiny, which is usually an icon rather than a wordmark), reasonable dimensions, and not a photograph. A quick edge-density check separates vector-ish marks from photos well enough.&lt;/p&gt;

&lt;p&gt;I extract the aspect ratio explicitly and store it as a token, because header height depends on it and a 6:1 wordmark and a 1:1 mark produce meaningfully different headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screenshots are for verification, never extraction
&lt;/h2&gt;

&lt;p&gt;The most useful architectural decision I made.&lt;/p&gt;

&lt;p&gt;It is tempting to pull colors out of a screenshot — it works, it's simple, and it handles canvas and image-heavy sites where the DOM tells you nothing. But screenshot pixels have been through compositing, anti-aliasing, and JPEG artifacts. The color you sample is &lt;em&gt;near&lt;/em&gt; the brand color, never equal to it. Downstream, near-correct tokens produce output that looks subtly wrong in a way that is very hard to debug.&lt;/p&gt;

&lt;p&gt;The DOM has ground truth. Use it.&lt;/p&gt;

&lt;p&gt;Screenshots earn their place at the &lt;em&gt;end&lt;/em&gt;: render the themed output, screenshot it, diff it against the source screenshot, and use the mismatch as a quality signal. Sub-5% pixel mismatch means the token extraction did its job. A large mismatch localized to one region tells you which token is wrong — a header-region mismatch points at logo sizing, a body-wide one points at type scale.&lt;/p&gt;

&lt;p&gt;Verification, not source. That distinction is the whole thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure modes worth knowing about
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Heavy canvas or WebGL sites.&lt;/strong&gt; The DOM is nearly empty. There is no good answer; these get flagged for manual handling rather than producing confident garbage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aggressive bot protection.&lt;/strong&gt; Some fraction of sites will not load headless. Budget for a fallback fetching path and accept that a percentage will need a human.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sites mid-rebrand.&lt;/strong&gt; New homepage, old interior pages. Extracting from more than one URL and detecting disagreement catches this, but resolving it requires knowing which one is current, which requires a human.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dark mode defaults.&lt;/strong&gt; If the extraction runs with a dark color-scheme preference and the brand's primary identity is light, every token is inverted. Pin the preference explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general lesson
&lt;/h2&gt;

&lt;p&gt;The scraping is the easy part and it is not where the quality comes from. The quality comes from the &lt;em&gt;interpretation layer&lt;/em&gt; — prominence weighting, role assignment, ratio fitting, deriving tokens from other tokens rather than collecting them independently.&lt;/p&gt;

&lt;p&gt;Which is a fairly ordinary engineering lesson dressed in an unusual problem: the value is in the model you impose on the data, not in the collection of it.&lt;/p&gt;

</description>
      <category>designsystems</category>
      <category>css</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What building 40+ product demos taught me about software</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Mon, 03 Aug 2026 21:24:20 +0000</pubDate>
      <link>https://dev.to/hugonaili/what-building-40-product-demos-taught-me-about-software-1dp5</link>
      <guid>https://dev.to/hugonaili/what-building-40-product-demos-taught-me-about-software-1dp5</guid>
      <description>&lt;p&gt;I've spent the better part of a year building demo environments for a living. Not prototypes, not MVPs, not production apps. Demos: software whose entire purpose is to be watched for eleven minutes by someone deciding whether to spend money.&lt;/p&gt;

&lt;p&gt;It is a strange discipline. Most of what I learned as a frontend engineer over the previous decade applies, but the priorities invert in ways that took me months to internalize. Here is what actually transferred, what didn't, and what I got wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo is a narrative, and the code serves it
&lt;/h2&gt;

&lt;p&gt;The first demo I built was technically excellent and completely useless.&lt;/p&gt;

&lt;p&gt;I had built a content modeling walkthrough with proper error boundaries, optimistic updates, a loading skeleton for every async boundary, and a genuinely nice type-safe API layer. During the run-through, the account executive stopped me forty seconds in and asked why we were looking at a spinner.&lt;/p&gt;

&lt;p&gt;The answer was that I had built for a real network. But nobody in a demo cares about a real network. They care about the moment where the thing they were promised happens on screen. Every millisecond before that moment is a millisecond where attention leaks.&lt;/p&gt;

&lt;p&gt;The reframe that helped: a demo is a story with a claim, and every screen either advances the claim or dilutes it. Loading states dilute. Empty states dilute. Error handling — which I still believe is the most underrated skill in frontend engineering — dilutes, because the error never comes.&lt;/p&gt;

&lt;p&gt;This does not mean building carelessly. It means the quality bar moves from &lt;em&gt;robustness under adverse conditions&lt;/em&gt; to &lt;em&gt;legibility under observation&lt;/em&gt;. Those are different targets and they require different code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seed data is the product
&lt;/h2&gt;

&lt;p&gt;I underestimated this for an embarrassingly long time.&lt;/p&gt;

&lt;p&gt;In production apps, seed data is a development convenience. You write a script, it fills the database with &lt;code&gt;user_1@example.com&lt;/code&gt; and Lorem Ipsum, and you get on with the real work. The data is scaffolding.&lt;/p&gt;

&lt;p&gt;In a demo, the data &lt;em&gt;is&lt;/em&gt; the demo. When a prospect in commercial real estate looks at a content dashboard, the difference between "Article Title 1" and "Q3 Leasing Trends: Suburban Office Absorption" is the difference between watching a tool and seeing their own job.&lt;/p&gt;

&lt;p&gt;I now spend more time on seed data than on components. A realistic dataset needs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plausible volume.&lt;/strong&gt; Three records looks like a toy. Three thousand looks like a database dump. Somewhere between forty and two hundred, depending on the entity, feels like a real workspace that a real team has been using for a real year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temporal spread.&lt;/strong&gt; Everything created on the same day is a tell. Real data has a long tail — things from last week, things from eight months ago, one thing from 2019 nobody has touched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deliberate imperfection.&lt;/strong&gt; A workspace where every field is filled and every image is present looks synthetic. One draft with no cover image, one entry with a slightly-too-long title that wraps, one archived item. These read as authenticity precisely because a designer would have removed them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Names that sound like the industry.&lt;/strong&gt; This is the highest-leverage detail and the cheapest to get right. Ten minutes reading a prospect's actual site gives you the vocabulary their team uses internally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast beats correct, until it doesn't
&lt;/h2&gt;

&lt;p&gt;The tension I still haven't fully resolved.&lt;/p&gt;

&lt;p&gt;Demos have brutal timelines. A prospect meeting gets scheduled Thursday for the following Tuesday, the environment needs to reflect their brand and their content model, and there is no version of that where you architect carefully.&lt;/p&gt;

&lt;p&gt;So you take on debt aggressively. Hardcode the thing. Skip the abstraction. Put the mock response in a JSON file next to the component. This is correct and I would do it again.&lt;/p&gt;

&lt;p&gt;The failure mode is that demo environments do not die. They get forked. Someone on another team sees the commercial real estate demo, changes six strings, and now there are two. Then eight. Then the original has a bug and the bug is in all of them.&lt;/p&gt;

&lt;p&gt;What I settled on: &lt;strong&gt;debt is fine inside a demo, but never in the substrate.&lt;/strong&gt; The theming layer, the seed data generator, the deployment pipeline — those get real engineering, because every future demo inherits them. The narrative-specific code on top can be as disposable as it needs to be.&lt;/p&gt;

&lt;p&gt;The line is not "how important is this code" but "how many future demos will touch this code."&lt;/p&gt;

&lt;h2&gt;
  
  
  Theming is where the actual engineering lives
&lt;/h2&gt;

&lt;p&gt;The most interesting technical problem in this job is making one codebase convincingly wear another company's identity.&lt;/p&gt;

&lt;p&gt;Naively this is a color swap. In practice, brands differ along dimensions that break layouts in ways color never does. Type scale — a brand with a 72px display heading and a brand with a 32px one need different vertical rhythm, not a different font size. Border radius — a fully-rounded brand and a sharp-cornered brand imply different densities, different button padding, different card spacing. Logo aspect ratio, which quietly dictates header height and therefore every above-the-fold decision on the page.&lt;/p&gt;

&lt;p&gt;Once I stopped treating theming as a palette problem and started treating it as a constraint-propagation problem, the whole thing got tractable. Design tokens with derived values rather than fixed ones. Spacing that scales from a type ratio. Component padding expressed as a function of border radius rather than a magic number.&lt;/p&gt;

&lt;p&gt;This is the part of demo engineering that is genuinely just good frontend architecture, and it's the part I'd point to if someone asked whether this role keeps you sharp.&lt;/p&gt;

&lt;h2&gt;
  
  
  What transferred and what didn't
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Transferred:&lt;/strong&gt; component architecture, TypeScript discipline, understanding of the render cycle, CSS layout fundamentals, deployment tooling. All of it, more than I expected. A demo that stutters during a scroll is a demo that loses the room, and knowing why it stutters is a frontend skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did not transfer:&lt;/strong&gt; my instincts about what to build first. In product work you build the risky thing first to de-risk the project. In demo work you build the &lt;em&gt;visible&lt;/em&gt; thing first, because the visible thing is the entire deliverable and the risky thing may never be seen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actively harmful:&lt;/strong&gt; the completionist reflex. The urge to handle the edge case, fill in the empty state, wire up the setting that nobody will click. In product work that reflex is professionalism. Here it is scope creep against a fixed deadline, and I have burned real hours on screens that were never opened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable part
&lt;/h2&gt;

&lt;p&gt;There is a version of this job that is dishonest, and the line is thinner than I'd like.&lt;/p&gt;

&lt;p&gt;A demo shows software working. It does not show software working &lt;em&gt;under the conditions the prospect will actually encounter&lt;/em&gt;. Every demo engineer knows this. The good ones hold a line about which shortcuts are presentational and which are load-bearing.&lt;/p&gt;

&lt;p&gt;My rule: I will fake the &lt;em&gt;data&lt;/em&gt;, never the &lt;em&gt;capability&lt;/em&gt;. Seed data can be invented. Response times can be optimistic. But if the demo shows a feature, the feature exists, and if the demo implies an integration works, the integration works. The moment you demo something that cannot be built is the moment you have written a check the implementation team has to cash.&lt;/p&gt;

&lt;p&gt;That rule has cost me a few impressive-looking screens. It has also meant I have never had a post-sale conversation where someone felt misled, which I consider the actual measure of doing this job well.&lt;/p&gt;

</description>
      <category>demos</category>
      <category>softwaredevelopment</category>
      <category>frontend</category>
      <category>careertips</category>
    </item>
    <item>
      <title>How to type third-party API responses in TypeScript (without lying to your compiler)</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Sat, 13 Jun 2026 19:52:16 +0000</pubDate>
      <link>https://dev.to/hugonaili/how-to-type-third-party-api-responses-in-typescript-without-lying-to-your-compiler-4cdn</link>
      <guid>https://dev.to/hugonaili/how-to-type-third-party-api-responses-in-typescript-without-lying-to-your-compiler-4cdn</guid>
      <description>&lt;p&gt;You add TypeScript to a project, turn on &lt;code&gt;strict&lt;/code&gt;, fix every red squiggle, and feel safe. Then a third-party API quietly changes a field from a number to a string, your app explodes in production, and TypeScript never said a word.&lt;/p&gt;

&lt;p&gt;That gap surprises people, so it's worth saying plainly: &lt;strong&gt;TypeScript checks your code, not the data your code receives at runtime.&lt;/strong&gt; The moment a value crosses the network boundary, your types are a promise nobody is enforcing. This article walks through how to type API responses honestly — from the quick approaches that only &lt;em&gt;look&lt;/em&gt; safe, to the ones that actually hold up when the data misbehaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The starting point: &lt;code&gt;fetch&lt;/code&gt; gives you nothing
&lt;/h2&gt;

&lt;p&gt;Here's the shape of the problem. The built-in &lt;code&gt;fetch&lt;/code&gt; returns a response whose &lt;code&gt;.json()&lt;/code&gt; resolves to &lt;code&gt;any&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.example.com/users/1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// user: any&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;naem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// typo, no error, crashes at runtime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;any&lt;/code&gt; switches type checking off. Every property access is allowed, including the typo. So the first instinct is usually to reach for a type assertion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: &lt;code&gt;as&lt;/code&gt; assertions
&lt;/h2&gt;

&lt;p&gt;This compiles, and it's tempting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your editor autocompletes &lt;code&gt;user.name&lt;/code&gt; and the typo is caught. It feels solved. It isn't.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;as&lt;/code&gt; is you telling the compiler "trust me, this is a &lt;code&gt;User&lt;/code&gt;." The compiler stops arguing and assumes you're right. But nothing checks the actual JSON. If the API returns &lt;code&gt;{ "id": "1", "name": null }&lt;/code&gt;, TypeScript still believes &lt;code&gt;name&lt;/code&gt; is a &lt;code&gt;string&lt;/code&gt;, and &lt;code&gt;user.name.toUpperCase()&lt;/code&gt; throws &lt;code&gt;Cannot read properties of null&lt;/code&gt; in production — exactly the failure types were supposed to prevent.&lt;/p&gt;

&lt;p&gt;A type assertion doesn't &lt;em&gt;verify&lt;/em&gt; anything. It &lt;em&gt;silences&lt;/em&gt; the one part of your stack that was being honest about not knowing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step one: generics for a reusable typed wrapper
&lt;/h2&gt;

&lt;p&gt;Before we fix the runtime problem, let's at least stop repeating ourselves. A small generic wrapper lets each call site say what it expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Request failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getJson&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.example.com/users/1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// user is typed as User&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is genuinely useful: the &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; flows through, so every caller gets a typed result without scattering assertions everywhere. The error handling lives in one place.&lt;/p&gt;

&lt;p&gt;But be honest about what it does and doesn't do. That &lt;code&gt;as Promise&amp;lt;T&amp;gt;&lt;/code&gt; inside the wrapper is the same assertion as before, just hidden one level down. The ergonomics improved; the runtime safety did not. The data is still unverified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step two: validate at the boundary with a schema
&lt;/h2&gt;

&lt;p&gt;The real fix is to check the data once, at the edge where it enters your app, and only hand the rest of your code values that have actually been verified. A schema validation library like &lt;a href="https://zod.dev" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; makes this the path of least resistance.&lt;/p&gt;

&lt;p&gt;The key idea: you write the &lt;strong&gt;schema&lt;/strong&gt; as the single source of truth, and &lt;em&gt;derive&lt;/em&gt; the TypeScript type from it — instead of writing an &lt;code&gt;interface&lt;/code&gt; and a separate validator that drift apart over time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Derive the type from the schema — one source of truth.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// start from unknown, not any&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// throws if the payload doesn't match&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things changed that matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;json&lt;/code&gt; starts as &lt;code&gt;unknown&lt;/code&gt;, not &lt;code&gt;any&lt;/code&gt;. &lt;code&gt;unknown&lt;/code&gt; forces you to prove what the value is before you can use it — the compiler won't let you skip the check.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserSchema.parse(json)&lt;/code&gt; actually inspects the data at runtime. If the API returns &lt;code&gt;{ "id": "1", ... }&lt;/code&gt; with a stringy id, it throws a &lt;code&gt;ZodError&lt;/code&gt; immediately, at the boundary, with a clear message — instead of three components deep when you try to do math on it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather handle bad data as a value than a thrown exception, use &lt;code&gt;safeParse&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// result.error.issues is an array of every problem found&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// result.data is fully typed AND verified here&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested both paths against a deliberately malformed payload (&lt;code&gt;id&lt;/code&gt; as a string, invalid email): &lt;code&gt;parse&lt;/code&gt; throws a &lt;code&gt;ZodError&lt;/code&gt;, and &lt;code&gt;safeParse&lt;/code&gt; returns &lt;code&gt;success: false&lt;/code&gt; with two issues — one per bad field. That's the difference between "TypeScript thinks this is fine" and "this data is provably correct."&lt;/p&gt;

&lt;h2&gt;
  
  
  Step three: codegen, when the API already has a schema
&lt;/h2&gt;

&lt;p&gt;Hand-writing schemas is the right call for APIs you don't control or that have no machine-readable contract. But if the API publishes one, generate your types from it instead of transcribing them by hand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;REST with an OpenAPI/Swagger spec&lt;/strong&gt; → &lt;a href="https://github.com/openapi-ts/openapi-typescript" rel="noopener noreferrer"&gt;&lt;code&gt;openapi-typescript&lt;/code&gt;&lt;/a&gt; turns the spec into types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GraphQL&lt;/strong&gt; → &lt;a href="https://the-guild.dev/graphql/codegen" rel="noopener noreferrer"&gt;GraphQL Code Generator&lt;/a&gt; produces types from your schema and even your individual queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Codegen's advantage is that the types are mechanically tied to the contract: when the API's spec changes and you regenerate, the new or removed fields show up as type errors across your codebase, pointing you straight at what broke. The tradeoff is that most codegen describes the &lt;em&gt;shape&lt;/em&gt; at build time; it doesn't, by itself, validate the actual response at runtime. For untrusted or flaky sources, people often pair generated types with a runtime check at the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which approach should you reach for?
&lt;/h2&gt;

&lt;p&gt;There's no single winner — it depends on how much you trust the source and what the API gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Internal API you control, low risk, want speed:&lt;/strong&gt; a generic &lt;code&gt;getJson&amp;lt;T&amp;gt;&lt;/code&gt; wrapper with hand-written interfaces is fine. Just know the runtime is unchecked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party or user-facing data, correctness matters:&lt;/strong&gt; validate at the boundary with a schema (Zod or similar) and derive your types from it. This is the default I'd recommend for anything important.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API ships an OpenAPI or GraphQL schema:&lt;/strong&gt; generate types from the contract, and add a runtime check at the edge if the data is untrusted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice the through-line: the safest options all push verification to the &lt;strong&gt;boundary&lt;/strong&gt; and keep a &lt;strong&gt;single source of truth&lt;/strong&gt; for the type. Everything inside your app then works with data that's already been proven to match its type — which is the actual promise TypeScript was supposed to give you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;TypeScript types describe what your data &lt;em&gt;should&lt;/em&gt; be. They don't make it so. For data you generate inside your own code, that's enough. For data arriving over the network, you need something that checks reality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reach for &lt;strong&gt;generics&lt;/strong&gt; to stop repeating type assertions, but don't mistake nicer ergonomics for safety.&lt;/li&gt;
&lt;li&gt;Avoid &lt;code&gt;as&lt;/code&gt; on API responses — it silences the compiler instead of verifying the data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate at the boundary&lt;/strong&gt; with a schema and infer your types from it, so the type and the check can never drift apart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate types&lt;/strong&gt; from an OpenAPI or GraphQL contract when one exists, and validate at runtime when the source is untrusted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do that, and the next time an API quietly changes a field, you find out at the boundary with a clear error — not from a user, in production, three layers deep.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>TypeScript vs. JavaScript: Explaining the differences</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Thu, 07 May 2026 00:16:21 +0000</pubDate>
      <link>https://dev.to/hugonaili/typescript-vs-javascript-explaining-the-differences-41n4</link>
      <guid>https://dev.to/hugonaili/typescript-vs-javascript-explaining-the-differences-41n4</guid>
      <description>&lt;p&gt;TypeScript provides developers many advantages over JavaScript: you can identify and enforce data types, better communicate the purpose of code, and streamline your development process with enhanced developer tools.&lt;/p&gt;

&lt;p&gt;This article explains the difference between TypeScript and JavaScript, how to take advantage of the new features, and how to migrate your projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is JavaScript?
&lt;/h2&gt;

&lt;p&gt;JavaScript is a high-level interpreted programming language that's been around since 1995 and is widely used in web development.&lt;/p&gt;

&lt;p&gt;It was originally developed for adding interactivity and functionality to HTML web pages. It can manipulate the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model" rel="noopener noreferrer"&gt;Document Object Model (DOM)&lt;/a&gt;, making it possible to create dynamic and responsive user interfaces that run in the web browser.&lt;/p&gt;

&lt;p&gt;Although JavaScript is best known for being a client-side language, developers' widespread familiarity with it led to it being used server-side using Node.js, and to develop mobile and desktop apps using frameworks like &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic&lt;/a&gt; and &lt;a href="https://www.electronjs.org/" rel="noopener noreferrer"&gt;Electron&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is TypeScript?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.contentful.com/blog/what-is-typescript-and-why-should-you-use-it/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; is a programming language that's a superset of JavaScript — building on top of it to add &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Static_typing" rel="noopener noreferrer"&gt;static typing&lt;/a&gt; so you can catch errors during development instead of at runtime.&lt;/p&gt;

&lt;p&gt;It was developed by Microsoft to address the difficulties of maintaining large applications written in JavaScript, and has been expanded to add a number of modern developer-friendly features.&lt;/p&gt;

&lt;p&gt;In addition to static typing, TypeScript also adds features like &lt;a href="https://www.typescriptlang.org/docs/handbook/interfaces.html" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org/docs/handbook/2/generics.html" rel="noopener noreferrer"&gt;generics&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org/docs/handbook/type-inference.html" rel="noopener noreferrer"&gt;type inference&lt;/a&gt;, &lt;a href="https://www.scholarhat.com/tutorial/typescript/access-modifiers" rel="noopener noreferrer"&gt;access modifiers&lt;/a&gt;, and other constructs not present in standard JavaScript.&lt;/p&gt;

&lt;p&gt;TypeScript compiles to plain JavaScript, so anything that works in JavaScript works in TypeScript, including third-party JavaScript libraries and any code you've already written in JavaScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's the difference between TypeScript and JavaScript?
&lt;/h2&gt;

&lt;p&gt;Both TypeScript and JavaScript are widely used for web development. As they are so closely related, they're often confused, but the key differences between TypeScript and JavaScript are as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqb6i32a8ry51fmp4auk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqb6i32a8ry51fmp4auk.png" alt="The difference between TypeScript and JavaScript" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is static typing?
&lt;/h2&gt;

&lt;p&gt;Static typing is a programming language feature that lets you explicitly specify the data types of variables, function parameters, and return values in advance, so they are known at compile time. For TypeScript, this means the code is checked for type-related errors when it's compiled to JavaScript, so type-related errors are caught &lt;em&gt;before&lt;/em&gt; they reach users.&lt;/p&gt;

&lt;p&gt;By contrast, JavaScript has &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Dynamic_typing" rel="noopener noreferrer"&gt;dynamic typing&lt;/a&gt;. This is where data types are determined and checked at runtime, meaning that if there is a type-related error (like trying to multiply a string by an integer), it won't be encountered until someone finds the bug by running the code — which could be one of your users in production.&lt;/p&gt;

&lt;p&gt;Static typing in TypeScript ensures that variables are used in ways consistent with their defined types, preventing certain types of errors that can occur due to incorrect type usage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example of static typing in TypeScript
&lt;/h2&gt;

&lt;p&gt;An example of a type error is shown in the below JavaScript snippet. This code assigns a string to the &lt;code&gt;age&lt;/code&gt; variable, even though it was originally supposed to be a number. This leads to a runtime error when the code later tries to use &lt;code&gt;age&lt;/code&gt; in a numeric context.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let age = 25;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;age = "twenty six";&lt;/code&gt;&lt;br&gt;
&lt;code&gt;console.log(age * 2); // runtime error: "NaN"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fet3x6jmavzllhpl83uqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fet3x6jmavzllhpl83uqn.png" alt="JavaScript causes a NaN error in the browser" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The above JavaScript causes a NaN error in the browser.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Using a string in a numerical context results in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" rel="noopener noreferrer"&gt;NaN (Not a Number)&lt;/a&gt;, a special value that indicates an operation has failed due to a number conversion.&lt;/p&gt;

&lt;p&gt;With TypeScript, adding a static &lt;code&gt;number&lt;/code&gt; type to the &lt;code&gt;age&lt;/code&gt; variable causes the compiler to immediately raise the issue:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;let age: number = 25;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;age = "twenty six"; // compiler error: "Type 'string' is not assignable to type 'number'."&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sipesw4qigtu6sbwygw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sipesw4qigtu6sbwygw.png" alt="The above TypeScript causes an error earlier — before runtime." width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The above TypeScript causes an error earlier — before runtime.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Benefits of static typing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Early error detection&lt;/strong&gt; — Type-related errors are caught at compile time, helping developers identify and fix issues before the code is executed. Many modern code editors (e.g., &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;) support the TypeScript compiler running automatically in the background, meaning errors are caught as you write code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved code quality&lt;/strong&gt; — Type annotations make your code self-documenting and easier to understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced tooling&lt;/strong&gt; — IDEs and code editors can provide better auto-completion, code navigation, and refactoring suggestions based on type information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability and maintainability&lt;/strong&gt; — Explicit types make code more readable and understandable, especially in larger projects.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  TypeScript vs. JavaScript: use cases
&lt;/h2&gt;
&lt;h3&gt;
  
  
  When to use JavaScript
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;When learning to code for the first time&lt;/strong&gt; — Beginner developers may prefer to experiment with JavaScript's flexible code without being overwhelmed with extra information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For ad-hoc scripts or automation tasks&lt;/strong&gt; — When you're automating tasks or writing quick, throwaway scripts, JavaScript is quicker to set up and get started with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When working on legacy codebases&lt;/strong&gt; — If you're working on a very old codebase already written in JavaScript, it may not be worth converting it all to TypeScript, which could require significant rewrites or break existing functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  When to use TypeScript (hint: whenever you can!)
&lt;/h3&gt;

&lt;p&gt;You should use TypeScript whenever you can. The advantages it provides are numerous, and in any application of any scale, it gives you a better developer experience that results in more reliable code. This is particularly important for complex projects that involve collaboration between teams.&lt;/p&gt;


&lt;h2&gt;
  
  
  Is TypeScript better than JavaScript?
&lt;/h2&gt;

&lt;p&gt;TypeScript vs. JavaScript has a clear winner for large collaborative projects. Here's why TypeScript can be a game-changer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced errors&lt;/strong&gt; — Static typing helps catch type-related errors at compile time, preventing many common mistakes from reaching runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved tooling and IDE support&lt;/strong&gt; — TypeScript provides robust tooling, including code completion, navigation, and refactoring suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced collaboration&lt;/strong&gt; — Type annotations provide clear interfaces for functions and modules, making it easier for team members to understand how different parts of the codebase interact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safer refactoring&lt;/strong&gt; — TypeScript's type system makes refactoring safer by alerting developers to potential issues when they change code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code quality and consistency&lt;/strong&gt; — TypeScript encourages a higher level of code quality and consistency by enforcing type standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code maintainability&lt;/strong&gt; — Static typing makes it easier to understand the data types of variables, function parameters, and return values, resulting in more self-documenting code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need to take an all-or-nothing approach. You can adopt TypeScript incrementally — start by adding types to new code or the most error-prone parts of your codebase.&lt;/p&gt;


&lt;h2&gt;
  
  
  How to migrate your existing JavaScript project to TypeScript
&lt;/h2&gt;

&lt;p&gt;Ensure you have the latest versions of Node.js and npm installed, then follow these steps:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Install TypeScript
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;typescript &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Create tsconfig.json
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This creates a basic TypeScript configuration.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Enable JavaScript support
&lt;/h3&gt;

&lt;p&gt;To allow TypeScript to compile &lt;code&gt;.js&lt;/code&gt; files during migration, add &lt;code&gt;"allowJs": true&lt;/code&gt; to the &lt;code&gt;compilerOptions&lt;/code&gt; object in &lt;code&gt;tsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowJs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Convert your JavaScript files to TypeScript
&lt;/h3&gt;

&lt;p&gt;Rename &lt;code&gt;*.js&lt;/code&gt; files to &lt;code&gt;*.ts&lt;/code&gt; (or &lt;code&gt;*.jsx&lt;/code&gt; to &lt;code&gt;*.tsx&lt;/code&gt;). Then run the compiler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc path/to/your/file.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also convert all files at once and run &lt;code&gt;npx tsc&lt;/code&gt; to compile them all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Avoid renaming auto-generated files (e.g., those in &lt;code&gt;.next/&lt;/code&gt;) or files from external libraries in &lt;code&gt;node_modules/&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Add type annotations gradually
&lt;/h3&gt;

&lt;p&gt;Start small by adding types for function parameters and return values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then progressively add interfaces, type aliases, and more advanced TypeScript features.&lt;/p&gt;

&lt;p&gt;For third-party libraries, you can find type definitions in the &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped" rel="noopener noreferrer"&gt;DefinitelyTyped&lt;/a&gt; repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Run tests
&lt;/h3&gt;

&lt;p&gt;After migrating your files, &lt;a href="https://learn.microsoft.com/en-us/visualstudio/javascript/unit-testing-javascript-with-visual-studio?view=vs-2022&amp;amp;tabs=jest" rel="noopener noreferrer"&gt;run your test suites&lt;/a&gt; to check that everything still works and catch any breaking changes introduced during the migration.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What is the global object in JavaScript? A practical guide for developers</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Wed, 29 Apr 2026 01:27:05 +0000</pubDate>
      <link>https://dev.to/hugonaili/what-is-the-global-object-in-javascript-a-practical-guide-for-developers-58f3</link>
      <guid>https://dev.to/hugonaili/what-is-the-global-object-in-javascript-a-practical-guide-for-developers-58f3</guid>
      <description>&lt;p&gt;The JavaScript global object and scope are a key part of building apps with JavaScript. Unfortunately, they are easy to misunderstand and misuse, leading to negative impacts on your application's functionality, performance, and security.&lt;/p&gt;

&lt;p&gt;This guide covers what the global object is, how JavaScript scopes work, and how to safely create and access global variables and functions across different environments.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is the global object in JavaScript?
&lt;/h2&gt;

&lt;p&gt;The global object in JavaScript is available to all parts of your code. Any variables or functions inside it are in the &lt;strong&gt;global scope&lt;/strong&gt;, meaning they can be used in functions, nested callbacks, and modules — wherever they are.&lt;/p&gt;

&lt;p&gt;The global object has a different name depending on your environment:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;Global object&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;&lt;code&gt;window&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;&lt;code&gt;global&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Worker&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;self&lt;/code&gt; (or &lt;code&gt;this&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Because of this inconsistency, &lt;code&gt;globalThis&lt;/code&gt; was introduced to provide a single, standardized way to access the global object in any environment. More on that later.&lt;/p&gt;


&lt;h2&gt;
  
  
  The JavaScript global scope
&lt;/h2&gt;

&lt;p&gt;JavaScript &lt;strong&gt;scopes&lt;/strong&gt; (also called contexts) determine where a declared variable or function is accessible. Each scope has access to variables and functions declared in its parent scopes.&lt;/p&gt;

&lt;p&gt;When JavaScript resolves a variable name, it starts at the current scope and works upward toward the global scope. The first match it finds wins.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Global scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Variables and functions declared outside any module, function, or block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Module scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Variables and functions inside a module — isolated, not accessible from other modules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Function scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Variables and functions declared inside a function — only accessible within that function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Block scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Variables declared with &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt; inside &lt;code&gt;{}&lt;/code&gt; — only accessible within that block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note on local scope:&lt;/strong&gt; "Local scope" is an informal term that refers to either function scope or module scope, depending on context. A variable declared inside a function is local to that function; a variable declared inside a module is local to that module.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  When you should (and shouldn't) use the global object
&lt;/h2&gt;

&lt;p&gt;Each JavaScript environment comes with its own built-in globals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser&lt;/strong&gt; — &lt;code&gt;window&lt;/code&gt; exposes the DOM, alert popups, &lt;code&gt;console&lt;/code&gt;, &lt;code&gt;localStorage&lt;/code&gt;, geometry info, base64 utilities, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; — &lt;code&gt;global&lt;/code&gt; exposes module imports, &lt;code&gt;process.env&lt;/code&gt; for environment variables, timers, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workers&lt;/strong&gt; — additional globals for shared scope access between the window and other workers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These built-in globals are safe and intended to be used. Where you need to be careful is when &lt;strong&gt;adding your own variables to the global scope&lt;/strong&gt;. Avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Naming a variable the same as an existing built-in global&lt;/li&gt;
&lt;li&gt;Storing sensitive data (like user credentials or API tokens) in globals where they could be unintentionally exposed&lt;/li&gt;
&lt;li&gt;Reusing variable names across scopes, which can cause a function to silently read a global instead of a local value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over-relying on globals also has long-term costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Harder to debug&lt;/strong&gt; — globals can be modified from anywhere, making it difficult to trace unexpected values&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory overhead&lt;/strong&gt; — globals persist for the lifetime of the page or process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Namespace pollution&lt;/strong&gt; — too many globals increases the risk of naming conflicts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best practice is to use globals as strategically and sparingly as possible.&lt;/p&gt;


&lt;h2&gt;
  
  
  How to create and access global variables in JavaScript
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Scope&lt;/th&gt;
      &lt;th&gt;Set a global variable from this scope&lt;/th&gt;
      &lt;th&gt;Access a global variable from this scope&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Global&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;em&gt;Declared variables and functions are automatically global&lt;/em&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Browser:&lt;/strong&gt; &lt;code&gt;var myVariable = 'foo';&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt; &lt;code&gt;var myVariable = 'foo';&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Worker:&lt;/strong&gt; &lt;code&gt;var myVariable = 'foo';&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Browser:&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;code&gt;console.log(myVariable)&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;code&gt;console.log(myVariable)&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Worker:&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;code&gt;console.log(myVariable)&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Function/local/block&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;em&gt;Global variables/functions must be declared in the global object&lt;/em&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Browser:&lt;/strong&gt; &lt;code&gt;window.myVariable = 'foo';&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt; &lt;code&gt;global.myVariable = 'foo';&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Worker:&lt;/strong&gt; &lt;code&gt;this.myVariable = 'foo';&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Browser:&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;code&gt;console.log(window.myVariable)&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;code&gt;console.log(global.myVariable)&lt;/code&gt;&lt;/p&gt;
        &lt;p&gt;&lt;strong&gt;Worker:&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;code&gt;console.log(this.myVariable)&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Module&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;&lt;em&gt;Each module has its own global scope, so global variables declared in one module will not be present in another&lt;/em&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td colspan="2"&gt;
        &lt;p&gt;Within modules, global, function, and block scopes behave the same way as in other environments. Functions inside modules have their own function scope and must access the module's global scope through &lt;code&gt;window&lt;/code&gt;, &lt;code&gt;global&lt;/code&gt;, or &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to create and access global functions in JavaScript
&lt;/h2&gt;

&lt;p&gt;The process for global functions mirrors global variables. Declare a function at the top level and it is automatically global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Declared at the top level — automatically in the global scope&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Hello, world!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are inside a function or block scope, you must explicitly attach the function to the global object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Browser&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Hello, world!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Node.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Hello, world!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Watch out:&lt;/strong&gt; Variable names and function names share the same namespace in the global scope. A &lt;code&gt;var myFunction = ...&lt;/code&gt; will silently overwrite a &lt;code&gt;function myFunction() {}&lt;/code&gt; if they share the same name.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How to use &lt;code&gt;globalThis&lt;/code&gt; to access the global object from anywhere
&lt;/h2&gt;

&lt;p&gt;With multiple JavaScript environments in play — browser windows, Node.js, web workers — accessing the global object the old way required environment-sniffing code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The old way — fragile and verbose&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;globalObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;globalThis&lt;/code&gt; solves this by always returning the global object, regardless of where you call it from. It is now supported in all modern browsers and recent versions of Node.js.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting a global variable with &lt;code&gt;globalThis&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Works in browser, Node.js, and workers&lt;/span&gt;
&lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Accessing a global variable with &lt;code&gt;globalThis&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myVariable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 'foo'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setting a global function with &lt;code&gt;globalThis&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Accessing a global function with &lt;code&gt;globalThis&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;globalThis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Hello, world!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;globalThis&lt;/code&gt; works by calling &lt;code&gt;this&lt;/code&gt; from the global scope, which always returns the global object — even when you're inside a function, a module, or a worker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The global object (&lt;code&gt;window&lt;/code&gt;, &lt;code&gt;global&lt;/code&gt;, &lt;code&gt;self&lt;/code&gt;) holds all globally scoped variables and functions and is accessible throughout your entire codebase.&lt;/li&gt;
&lt;li&gt;JavaScript resolves variable names by walking up the scope chain — the first match wins.&lt;/li&gt;
&lt;li&gt;Use built-in environment globals freely, but be strategic when adding your own.&lt;/li&gt;
&lt;li&gt;Over-relying on globals leads to debugging difficulties, memory overhead, and naming conflicts.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;globalThis&lt;/code&gt; as the universal, environment-agnostic way to read and write globals.&lt;/li&gt;
&lt;li&gt;When possible, prefer modules for sharing code rather than adding to the global scope.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>globalthis</category>
      <category>node</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Vue vs. React: Which JavaScript UI framework is best?</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Tue, 28 Apr 2026 23:20:16 +0000</pubDate>
      <link>https://dev.to/hugonaili/vue-vs-react-which-javascript-ui-framework-is-best-1coc</link>
      <guid>https://dev.to/hugonaili/vue-vs-react-which-javascript-ui-framework-is-best-1coc</guid>
      <description>&lt;p&gt;Choosing the right UI framework can make a big difference to your project's success. Vue and React are two of the most popular frameworks for UI development, and both offer huge improvements in development speed and useful functionality over vanilla JavaScript. Both are lightweight and modular with a component-based architecture and rely on a virtual DOM to improve performance. But which is best?&lt;/p&gt;

&lt;p&gt;The truth is that there isn't one clear winner for all possible use cases, but it's likely that one will be better than another for your specific project. So, to understand which framework will work best for you, you'll need to consider which is the best fit for the developers in your team, and for the type and size of your particular application. &lt;/p&gt;

&lt;p&gt;This post provides detailed, practical comparisons between React and Vue that will help you make an informed decision about leveraging either for your project's specific needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Vue?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; is a front-end framework for building UIs, developed by Evan You (a former Google engineer) in 2014, and is particularly well suited for building &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA" rel="noopener noreferrer"&gt;single-page applications&lt;/a&gt; (SPAs). It's a progressive framework, which means you can adopt it incrementally, starting by plugging just one part of it into an existing application. This incremental approach makes it easy to integrate into existing projects as well as new ones.&lt;/p&gt;

&lt;p&gt;Vue is known for having a gentle learning curve. One reason behind this is its HTML-based template syntax, which is easier to get started with than learning a new syntax from scratch. Another reason is its use of single file components — files with a .vue suffix that contain HTML, CSS, and JavaScript all together. An example of the template syntax within a single file component is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;changeMessage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/template&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;changeMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You clicked the button!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="nx"&gt;scoped&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/style&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, you'll notice the use of one of &lt;a href="https://vuejs.org/api/built-in-directives.html" rel="noopener noreferrer"&gt;Vue's directives&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Directives tell Vue to do something to a DOM element, and are prefixed with a v-. In the above example, the v-on:click directive handles the button being clicked. There are a wide variety of directives for different use cases, ranging from &lt;a href="https://vuejs.org/guide/essentials/class-and-style" rel="noopener noreferrer"&gt;v-bind&lt;/a&gt; (which allows you to dynamically bind a variable to an HTML element) to &lt;a href="https://vuejs.org/guide/essentials/list" rel="noopener noreferrer"&gt;v-for&lt;/a&gt; (which allows you to iterate over a list).&lt;/p&gt;

&lt;p&gt;As well as the standard HTML-based components like &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, Vue has its own built-in components, such as &lt;a href="https://vuejs.org/guide/built-ins/transition.html" rel="noopener noreferrer"&gt;&lt;/a&gt; for managing animation effects like fading a component in or out.&lt;/p&gt;

&lt;p&gt;The project structure of a Vue app looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fek9t81t4js0wcca8cdwf.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fek9t81t4js0wcca8cdwf.webp" alt="Vue projects structure" width="211" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;public&lt;/code&gt; directory is for static assets that are not processed by Webpack (like &lt;code&gt;index.html&lt;/code&gt; — the main HTML template), whereas assets processed by Webpack (such as images and fonts) live in the &lt;code&gt;assets&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;main.js&lt;/code&gt; file is the entry point for your application and App.vue is the root Vue component. All child components go in the components directory except page components, which go in &lt;code&gt;views&lt;/code&gt;. The router directory is for your Vue router configuration and &lt;code&gt;store&lt;/code&gt; is for state management. Finally, &lt;code&gt;vue.config.js&lt;/code&gt; is an optional configuration file for the Vue CLI.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is React?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; is a JavaScript library, originally developed by Facebook in 2013. Like Vue, it's also used for building UIs and SPAs, as well as more complex web applications.&lt;/p&gt;

&lt;p&gt;Although React is technically considered to be more of a library than a full-fledged framework, this distinction doesn't mean that it's less comprehensive than Vue, as the extra features that make Vue a framework (such as routing and state management) are still available to be used with React; they’re just not part of the core library. Instead, you could use &lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt; for state management and &lt;a href="https://reactrouter.com/" rel="noopener noreferrer"&gt;React Router&lt;/a&gt; for routing.&lt;/p&gt;

&lt;p&gt;Like Vue, React has a component-based architecture and uses a virtual DOM to improve performance. It also uses declarative syntax, however, instead of templating it uses JSX, a syntax extension of JavaScript allowing you to describe UI elements in React.&lt;/p&gt;

&lt;p&gt;The code example from Vue above would look like this in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyComponent.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Import the CSS file for styling&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You clicked the button!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;changeMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* MyComponent.css */&lt;/span&gt;
&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see above, the HTML tags are included as part of JSX, but the CSS is separate. (There are alternative approaches to this, such as &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt;, a library that allows you to add CSS as part of your React code, but this isn’t part of the core React library.)&lt;/p&gt;

&lt;p&gt;You can also create custom components in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Greeting.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then refer to them in another JSX file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Greeting name={name} /&amp;gt;&lt;/code&gt; React projects typically have this structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fih0irvvnv0xewk18hoag.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fih0irvvnv0xewk18hoag.webp" alt="React projects structure" width="249" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;public&lt;/code&gt; directory is for static assets (like &lt;code&gt;index.html&lt;/code&gt; or the favicon). The index.js file is the entry point for your application, and &lt;code&gt;App.js&lt;/code&gt; is the root React component. All child &lt;code&gt;components&lt;/code&gt; go in the components directory and pages go in &lt;code&gt;pages&lt;/code&gt;. Finally, the &lt;code&gt;services&lt;/code&gt; directory is for service logic such as API calls and the &lt;code&gt;store&lt;/code&gt; directory is for state management (e.g. Redux).&lt;/p&gt;




&lt;h2&gt;
  
  
  How do Vue and React differ?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Vue.js&lt;/th&gt;
      &lt;th&gt;React&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;More opinionated&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;Vue offers a single integrated solution with libraries that work together seamlessly.&lt;/p&gt;
        &lt;p&gt;It has its own built-in tools for things like state management and routing.&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;More customizable&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;It's a library, not a framework — with a massive ecosystem of third-party libraries to choose from.&lt;/p&gt;
        &lt;p&gt;React uses these third-party libraries to handle state management and routing.&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;HTML templates&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;React uses HTML templating syntax with directives (by default).&lt;/p&gt;
        &lt;p&gt;It's possible to configure Vue to use JSX but this is less common.&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;JSX&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;This is essentially just JavaScript, so you have the full power of JavaScript in your application.&lt;/p&gt;
        &lt;p&gt;Dynamic rendering is easier in JSX.&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Less commonly used&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;In terms of market share, Vue is used by 1.1% of all JavaScript websites.&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;More commonly used&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;React is used by 5.1% of all JavaScript websites. While it might not sound like a lot, this is 5x the usage of Vue.&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;Less community support and backing&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;Vue has a decent amount of community support but not as much as React. It doesn't have a huge corporate backer like Meta in React's case, but does have sponsorship from some medium-sized companies.&lt;/p&gt;
        &lt;p&gt;&lt;em&gt;Notable users:&lt;/em&gt; Alibaba, GitLab, Upwork, Wizz Air&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;More community support and backing&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;React is supported by a massive community and has corporate backing from Meta.&lt;/p&gt;
        &lt;p&gt;&lt;em&gt;Notable users:&lt;/em&gt; Instagram, Reddit, Airbnb, Netflix&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;A combination of one-way and two-way data binding&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;v-model, a directive for form input fields, does two-way data binding, which simplifies the handling of form inputs.&lt;/p&gt;
        &lt;p&gt;The v-bind directive does one-way data binding.&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;strong&gt;One-way data binding&lt;/strong&gt;&lt;/p&gt;
        &lt;p&gt;Data flows in one direction — from parent to child via props.&lt;/p&gt;
        &lt;p&gt;You can still implement things that require bi-directional data flows, such as with forms, but such functionality requires managing state, which adds some complexity to your application.&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to choose: React vs. Vue for your project
&lt;/h2&gt;

&lt;p&gt;You need to make informed framework selection decisions to avoid wasting time and resources and introducing technical debt. Thorough understanding of your needs (as much as that’s possible up front) and planning for them makes app development more straightforward and predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  For new projects
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React is best for large complex projects:&lt;/strong&gt; Complex and large projects usually benefit from flexible tooling, so that, over time, development teams can adapt the tooling to fit their needs and their scale exactly. React is a good fit for such projects because it has a smaller amount of built-in functionality in its core library. Teams can pick and choose additional tooling to suit their own needs. React also has an extensive ecosystem, making it more flexible, which is often required with larger or more complex projects. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vue is easier to learn:&lt;/strong&gt; For smaller projects that don't require the flexibility of React, Vue is the better choice as it's simpler and easier to learn. If you're not familiar with either framework you'll probably find Vue easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  For existing projects
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Vue is easier to integrate:&lt;/strong&gt; As Vue is a progressive framework, you can just add one small part to your application at a time, making it easy to start integrating into your existing JavaScript projects. It's fairly easy to add a single file component to an existing project.&lt;/p&gt;

&lt;p&gt;Compare this to React, where you have to create many more files and import a root component into your code. It's often simpler to start from scratch and create a whole new React project, migrating all the old code from your old project into the new one.&lt;/p&gt;

&lt;h3&gt;
  
  
  For rapid prototyping
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Vue is easier to learn:&lt;/strong&gt; If you already have experience with either React or Vue, stick with the one you know, but otherwise use Vue as it has the simplest learning curve.&lt;/p&gt;

&lt;h3&gt;
  
  
  For server-side rendering (SSR)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;It's a tie:&lt;/strong&gt; Both have adequate solutions for SSR. You can either use React with &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; or Vue with &lt;a href="https://nuxt.com/" rel="noopener noreferrer"&gt;Nuxt.js&lt;/a&gt;. So, it really comes down to other considerations that you might care about — such as whether you're looking for a more opinionated or a more flexible framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  For long-term reliability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;React has more support and backing:&lt;/strong&gt; Most importantly, it has corporate backing from one of the big tech giants (Meta), but it's also used more, by some of the biggest companies in the world, and has a bigger community of support.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a Vue project
&lt;/h2&gt;

&lt;p&gt;You can use the Vue CLI to create a new Vue project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Node and NPM.&lt;/li&gt;
&lt;li&gt;Install the Vue CLI: &lt;code&gt;npm install -g @vue/cli&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use the Vue CLI to create your new project: &lt;code&gt;vue create my-vue-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter your new project directory: &lt;code&gt;cd my-vue-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Start the Vue development server: &lt;code&gt;npm run serve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt; in your browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to create a React project
&lt;/h2&gt;

&lt;p&gt;The simplest way to create a React project is to use the &lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Node and NPM.&lt;/li&gt;
&lt;li&gt;Use Create React App to create your new project: &lt;code&gt;npx create-react-app my-react-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter your new project directory: &lt;code&gt;cd my-react-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Start the React development server: &lt;code&gt;npm start&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Navigate to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt; in your browser.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best practices for Vue and React development and maintenance
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TypeScript:&lt;/strong&gt; Whether you're using React or Vue, there are some best practices that are relevant for both. For example, we recommend using TypeScript instead of JavaScript for all React and Vue projects as its static typing will help catch many errors early (at compile time) and will also give you features like improved automatic code completion that will speed up your development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GraphQL:&lt;/strong&gt; A potentially helpful practice for both types of projects is to use GraphQL. GraphQL enables you to fetch all the data you need from a single endpoint, which is much more efficient than having to use multiple REST queries to get the same data. Using GraphQL for fetching data can massively increase your performance, although there is a learning curve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vue best practices
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use the key attribute with lists:&lt;/strong&gt; When it comes to using listing items, Vue uses the &lt;code&gt;v-for&lt;/code&gt; directive, and as this isn't plain JavaScript, it can be harder to understand exactly what it's doing, which can lead to unintended side effects. For example, items in a list can lose their state when they're updated, as their order isn't necessarily preserved. To avoid this, add a key attribute to your list. React also has a similar key property for dealing with lists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!--Don't do this--&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"item in items"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!--Do this--&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"item in items"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"item.id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't use &lt;code&gt;v-if&lt;/code&gt; with &lt;code&gt;v-for&lt;/code&gt;:
&lt;/h3&gt;

&lt;p&gt;If you want to filter a list or array, don't use the v-if directive with v-for, as this is very inefficient. Vue gives priority to v-for over v-if, meaning that every single element will be looped over before the v-if conditional is checked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--Don't do this--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
   &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;'item in items'&lt;/span&gt;
   &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;'item.available'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;br&gt;
Instead, extract this logic to your JavaScript code and use a filter within there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--Do this--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"item in availableItems"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;availableItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;available&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;
  
  
  React best practices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;React hooks:&lt;/strong&gt; Using hooks allows you to simplify your code by managing state, side effects, and context all from within functional components. Without this, you'd have to use class components, which contain a lot more boilerplate code and are less performant.&lt;/p&gt;

&lt;p&gt;The most common React hooks are &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt;, but you can also create your own custom hooks. &lt;code&gt;useState&lt;/code&gt; is responsible for managing state, and it returns the current state value along with a function to update it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;br&gt;
&lt;code&gt;useEffect&lt;/code&gt; focuses on separating side effects from your main code logic, which makes your code more modular, readable, and maintainable. The code below runs &lt;code&gt;useEffect&lt;/code&gt; after every render, and the side effect is that it updates the title of the web page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`You clicked &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Optional cleanup function&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cleanup on unmount or before next effect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; 

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;br&gt;
&lt;strong&gt;React Suspense:&lt;/strong&gt; This allows you to display a fallback component when waiting for your main components to load. Suspense is particularly useful when your components rely on data that you're fetching from an API that may not have loaded yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;StrictMode:&lt;/strong&gt; Wrapping a component (or your entire application) in &lt;a href="https://react.dev/reference/react/StrictMode" rel="noopener noreferrer"&gt;StrictMode&lt;/a&gt; will add extra checks and warnings to that component and its descendents, allowing you to identify potential problems and catch them early on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/React.StrictMode&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>vue</category>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>React vs. React Native: The difference, and which is best for you</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Tue, 28 Apr 2026 21:45:12 +0000</pubDate>
      <link>https://dev.to/hugonaili/react-vs-react-native-the-difference-and-which-is-best-for-you-4jm1</link>
      <guid>https://dev.to/hugonaili/react-vs-react-native-the-difference-and-which-is-best-for-you-4jm1</guid>
      <description>&lt;p&gt;Choosing between React vs. React Native for your project can be confusing. Both JavaScript user interface (UI) libraries serve similar purposes and use the same syntax, but their differences are important. React is designed for building user interfaces for web front ends, while React Native helps you build native mobile apps for Android and iOS.&lt;/p&gt;

&lt;p&gt;This article explains what React and React Native are and their differences, and provides context and information so that you can decide which to use for a particular project.&lt;/p&gt;

&lt;h2&gt;
  
  
  React and React Native are not the same thing
&lt;/h2&gt;

&lt;p&gt;React and React Native are two distinct JavaScript libraries for developing user interfaces. While React serves as the foundation for React Native, they are not the same thing, and serve different purposes when developing user interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; is intended for building user interfaces for web applications that run in the browser. It lets you create reusable UI components using your own designs implemented using CSS, or using a pre-built user interface library.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://reactnative.dev/" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; lets you use React to build mobile applications that look and behave like native applications. Rather than defining your own look and feel, it adopts the appearance of the native UI elements of the operating system (like buttons, lists, and inputs), while still letting you develop your own broader design using familiar React concepts and syntax.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both libraries use the same core React syntax and component-based architecture. &lt;/p&gt;

&lt;p&gt;Before deciding which JavaScript UI library to adopt for a project, it's worth understanding each in detail. As React Native is built on React, the programming knowledge is transferable, so it's less a matter of deciding which you will invest your time learning, and more about learning React and then identifying when it would be better to use React Native on a per-project basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is React?
&lt;/h2&gt;

&lt;p&gt;React is an open-source frontend JavaScript library that is developed specifically for building user interfaces for applications that run in a web browser. It lets you create reusable UI components (known as a component-based architecture), reducing the code you need to write and providing a consistent and efficient codebase.&lt;/p&gt;

&lt;p&gt;React uses JSX, an extension to JavaScript that lets you include the HTML for your reusable UI components alongside their JavaScript in the same file, which some developers prefer as it makes your codebase easier to understand and navigate.&lt;/p&gt;

&lt;p&gt;Another major feature of React is the &lt;a href="https://legacy.reactjs.org/docs/faq-internals.html" rel="noopener noreferrer"&gt;virtual DOM&lt;/a&gt;: a representation of the HTML document displayed in the browser that you can manipulate programmatically, and that React then automatically syncs to the real DOM as shown to the user. This feature lets you use React to make dynamic pages that don't have to reload to change their contents, with much less code than would be required if working from scratch.&lt;/p&gt;

&lt;p&gt;Due to React’s lightweight nature, you can use it to provide as little or as much interactivity in a web page as needed, and you can add it to existing projects. Alternatives to React for web development include Vue.js and Angular.  React is used by websites like Facebook, Instagram, and Netflix to power their user interfaces.&lt;/p&gt;

&lt;p&gt;Below is an example of an HTML list rendered in React using JSX syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the React module&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the React component &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// List data&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Fruit&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt; /&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt; &lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;so&lt;/span&gt; &lt;span class="nx"&gt;they&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;                &lt;span class="p"&gt;))}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What is React Native?
&lt;/h2&gt;

&lt;p&gt;React Native was developed so that React developers could create mobile apps with their existing React skill sets. It allows for efficient app development, as you can share much of your code between all of your web and native applications (Windows, iOS/iPadOS, and Android).&lt;/p&gt;

&lt;p&gt;In addition to letting you leverage existing React skills, tools, and techniques to cover cross-platform native app development, React Native lets you build applications that look and feel like they were designed for each platform from the ground up. &lt;/p&gt;

&lt;p&gt;Rather than building your own UI elements and interacting with a virtual DOM, you use React Native's buttons, lists, panels, and other included components to create applications that look like, animate like, and conform to the host’s design system. Apps built with React Native include Discord, Uber, and Skype.&lt;/p&gt;

&lt;p&gt;Below is an example of the same list as above, but implemented using React Native user interface elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the React module as well as the React Native UI element modules for View, Text, and FlatList&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FlatList&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the React Component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Apple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Sample list data&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Fruit&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt; 
            &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Item names in the example array are unique strings, so they can be used as the key&lt;/span&gt;
            &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;            &lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that while React and JSX syntax is used in both the React and React Native examples, the React example uses HTML elements like &lt;/p&gt; and &lt;ul&gt; whereas the React Native example uses native UI components like  and .

&lt;p&gt;The behavior of each example is the same, but the UI provided by React will require CSS to style it, whereas the React Native UI elements will automatically adopt the appearance of the mobile platform they are run on (it's worth noting that you can &lt;a href="https://reactnative.dev/docs/stylesheet" rel="noopener noreferrer"&gt;alter the appearance&lt;/a&gt; of React Native components).&lt;/p&gt;




&lt;h2&gt;
  
  
  What is React Native for Web?
&lt;/h2&gt;

&lt;p&gt;Web browsers don't include native UI components for React Native to display. &lt;a href="https://necolas.github.io/react-native-web/" rel="noopener noreferrer"&gt;React Native for Web&lt;/a&gt; makes it possible to deploy React Native apps for delivery to web browsers by providing a set of web-compatible HTML UI components to use in place of the missing native components.&lt;/p&gt;

&lt;p&gt;This allows you to use React Native to build both mobile and web applications, and while React Native for Web isn't a core part of React Native, it is widely supported and used by the React community, and is actively maintained.&lt;/p&gt;




&lt;h2&gt;
  
  
  React Native for macOS and Windows
&lt;/h2&gt;

&lt;p&gt;It’s also possible to use it to develop desktop applications using &lt;a href="https://github.com/microsoft/react-native-windows" rel="noopener noreferrer"&gt;React Native for Windows&lt;/a&gt; and &lt;a href="https://github.com/microsoft/react-native-macos" rel="noopener noreferrer"&gt;React Native for macOS&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  When should you use React?
&lt;/h2&gt;

&lt;p&gt;You should use React to build user interfaces for your web development projects when you:&lt;/p&gt;

&lt;p&gt;Want to benefit from the component-based architecture and interactivity React provides.&lt;/p&gt;

&lt;p&gt;Are building web applications that will run in a web browser.&lt;/p&gt;

&lt;p&gt;Need to design bespoke interfaces with unique visual elements that differ from the visual style of the host operating system.&lt;/p&gt;




&lt;h2&gt;
  
  
  When should you use React Native?
&lt;/h2&gt;

&lt;p&gt;You should use React Native when you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to take your React skills and use them to build native mobile or desktop apps.&lt;/li&gt;
&lt;li&gt;Require a consistent user interface that adopts the appearance of the host operating system.&lt;/li&gt;
&lt;li&gt;Are building native apps that you will publish to the &lt;a href="https://reactnative.dev/docs/publishing-to-app-store" rel="noopener noreferrer"&gt;Apple App Store&lt;/a&gt;, &lt;a href="https://reactnative.dev/docs/signed-apk-android" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;, and &lt;a href="https://microsoft.github.io/react-native-windows/docs/app-publishing" rel="noopener noreferrer"&gt;Microsoft Store&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Are developing an application that doesn't rely on HTML — React Native has no DOM, so everything must be constructed with React Native UI components.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Choosing the best tools for your project
&lt;/h2&gt;

&lt;p&gt;React is a powerful user interface development tool, greatly streamlining the frontend development process. React Native builds on this by letting you use React to build native mobile apps as well as web apps, for full platform coverage using the same language and tools.&lt;/p&gt;

&lt;p&gt;However, that doesn't mean React (or React Native) is necessarily right for your project: there are a number of other user interface libraries and technologies, each with their own use cases and advantages. In some cases, a full application framework may accelerate your development process by providing a code foundation and boilerplate functionality for your apps.&lt;/p&gt;


&lt;/ul&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>javascript</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Designing Demos That Don’t Lie: A Demo Engineer’s Guide</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Tue, 28 Apr 2026 21:19:33 +0000</pubDate>
      <link>https://dev.to/hugonaili/designing-demos-that-dont-lie-a-demo-engineers-guide-ng3</link>
      <guid>https://dev.to/hugonaili/designing-demos-that-dont-lie-a-demo-engineers-guide-ng3</guid>
      <description>&lt;p&gt;There’s a special kind of dread that comes from watching a demo you know will never survive first contact with a real codebase.&lt;/p&gt;

&lt;p&gt;On the surface, it looks slick: perfect sample data, pixel‑polished UI, a happy path that always works. Under the hood, it’s a one‑off build, stitched together just well enough to impress for 30 minutes and impossible to evolve into anything useful afterward.&lt;/p&gt;

&lt;p&gt;As a software engineer, my job is to avoid that trap.&lt;/p&gt;

&lt;p&gt;In this post, I’ll share how I think about building &lt;strong&gt;“honest demos”&lt;/strong&gt; or demos that are realistic, technically sound, and close enough to production patterns that developers can actually build on them later, no matter which CMS, framework, or hosting platform they prefer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a demo “honest”?
&lt;/h2&gt;

&lt;p&gt;To me, an honest demo has three properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The architecture resembles what a real team would build.&lt;/strong&gt; Same patterns: API‑first, composable services, framework choices that match the audience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The content model is production‑minded.&lt;/strong&gt; References, localization, slugs, images, authors, not just a single “blob of text” field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The handoff doesn’t feel like starting from scratch.&lt;/strong&gt; The code, content model, and workflows are structured enough that a dev team could fork it and ship something real.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don’t need a specific vendor to do this. Any modern stack that combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;headless CMS or content API&lt;/strong&gt;,
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;frontend framework&lt;/strong&gt; (React, Vue, Svelte, etc.), and
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;CI/CD + hosting setup&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;can support honest demos if you design with production in mind from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start from a real architecture, not a slide
&lt;/h2&gt;

&lt;p&gt;Before I open a CMS or write a line of code, I write down three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target audience:&lt;/strong&gt; Frontend devs? Full‑stack? Marketers with some dev support?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary job to be done:&lt;/strong&gt; “Spin up a blog,” “launch a campaign page,” “localize product content,” etc.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Likely stack:&lt;/strong&gt; React + Next.js, Vue + Nuxt, a static site generator, or something else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I map the architecture they’d recognize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content layer&lt;/strong&gt;: a headless CMS or content API that stores structured content and media.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend layer&lt;/strong&gt;: the framework handling routing, data fetching (SSR/SSG/ISR), and UI components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivery layer&lt;/strong&gt;: hosting/CDN where builds run and pages are served.&lt;/li&gt;
&lt;li&gt;Optional integrations: search, analytics, commerce, personalization, and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is that nothing in the diagram feels like “demo‑only magic.” If a developer can’t imagine deploying a variant of what you’ve drawn, it’s the wrong architecture for the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Model content like a real product, not a JSON blob
&lt;/h2&gt;

&lt;p&gt;The fastest way to make a demo feel fake is to dump everything into a single “body” field.&lt;/p&gt;

&lt;p&gt;Instead, aim for the smallest content model that still feels like production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For a blog‑style experience, that might be:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Post&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt; (short text)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;slug&lt;/code&gt; (short text, used in the URL)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;excerpt&lt;/code&gt; (long text)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;body&lt;/code&gt; (Rich Text or Markdown)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;coverImage&lt;/code&gt; (media)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;author&lt;/code&gt; (reference to &lt;code&gt;Author&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tags&lt;/code&gt; (short text or references)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;publishedDate&lt;/code&gt; (date/time)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Author&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bio&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;avatar&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If localization matters to the audience, enable locales on key fields and actually show what it looks like to manage multiple languages from a single content model.&lt;/p&gt;

&lt;p&gt;This does two things in a demo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It &lt;strong&gt;builds trust&lt;/strong&gt; with developers, because they recognize patterns they already use.&lt;/li&gt;
&lt;li&gt;It gives you natural opportunities to show the strengths of a structured content approach: references, localization, content reuse, and preview.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Stand on the shoulders of starters and the community
&lt;/h2&gt;

&lt;p&gt;You don’t get extra points for hand‑rolling everything.&lt;/p&gt;

&lt;p&gt;Most ecosystems now offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Official starters and templates&lt;/strong&gt; for frameworks like Next.js, Gatsby, Nuxt, Remix, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open‑source example apps&lt;/strong&gt; on GitHub that wire a frontend to a headless CMS or content API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starter kits from hosting providers&lt;/strong&gt; that cover routing, deployment, and environment variables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a demo engineer, treat these as &lt;strong&gt;scaffolding&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a starter to bootstrap content types, basic pages, and wiring to your content API.&lt;/li&gt;
&lt;li&gt;Swap in your own components, design system, and story.&lt;/li&gt;
&lt;li&gt;Prune anything that doesn’t support the narrative you’re trying to tell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The win: you spend less time on boilerplate and more time on the aspects that make your demo unique to the prospect such as their vertical, their channels, their workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Seed content that tells a believable story
&lt;/h2&gt;

&lt;p&gt;Even with a strong content model, your demo will fall flat if the content itself feels like lorem ipsum in disguise.&lt;/p&gt;

&lt;p&gt;Think in &lt;strong&gt;tiny narratives&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each page type, what’s the story?
A launch announcement, a seasonal campaign, an educational series, etc.&lt;/li&gt;
&lt;li&gt;For each persona in the room (developer, marketer, product manager), what do they care about seeing?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then seed content that reflects that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Posts that look like something a real company in that industry would write.&lt;/li&gt;
&lt;li&gt;Images and assets that match the brand and channel (hero images, thumbnails, icons).&lt;/li&gt;
&lt;li&gt;A few intentional edge cases: long titles, missing images, quirky tags — so you can show validation or fallback behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI tools can help generate this seed content quickly, as long as you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review it for accuracy and tone.&lt;/li&gt;
&lt;li&gt;Avoid inserting any real customer, personal, or internal data into prompts.&lt;/li&gt;
&lt;li&gt;Treat it as a draft that you refine, not as a source of truth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Design the demo as a workflow, not a tour
&lt;/h2&gt;

&lt;p&gt;The most compelling demos are &lt;strong&gt;guided workflows&lt;/strong&gt;, not feature checklists.&lt;/p&gt;

&lt;p&gt;Instead of “here’s the content model, here’s the API, here’s the app,” frame the demo around a task that matches the audience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Let’s launch a new campaign page globally in under 10 minutes.”&lt;/li&gt;
&lt;li&gt;“Let’s create a new blog post and send it to production without touching code.”&lt;/li&gt;
&lt;li&gt;“Let’s add a new content component and expose it safely to authors.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then walk through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content modeling&lt;/strong&gt; Add or tweak a field, explain why it’s structured that way, and how it avoids future rework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authoring &amp;amp; preview&lt;/strong&gt; Create/edit content in the CMS, show live preview in the frontend, highlight validation and governance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer experience&lt;/strong&gt; Jump into the codebase, show how content is fetched via the content API, and how components map cleanly to content types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment or publishing&lt;/strong&gt; Either trigger a deploy or a publish flow, depending on the story you’re telling.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end, the audience hasn’t just watched features, they’ve followed a realistic workflow from idea to live experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Leave behind something developers can actually use
&lt;/h2&gt;

&lt;p&gt;A good demo answers “Can this work?”&lt;br&gt;&lt;br&gt;
A great demo also answers “What happens after we sign?”&lt;/p&gt;

&lt;p&gt;Whenever possible, make sure the demo assets can become a &lt;strong&gt;starter kit&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A repo with:

&lt;ul&gt;
&lt;li&gt;A clear README (how to run locally, how to connect to a CMS, how to deploy).&lt;/li&gt;
&lt;li&gt;A minimal but realistic folder structure (pages/routes, components, a small library for API access, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A content setup that:

&lt;ul&gt;
&lt;li&gt;Uses content types you’d be comfortable extending in production.&lt;/li&gt;
&lt;li&gt;Avoids one‑off hacks that only exist to make the demo look good.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the demo is just a lightly customized version of an existing starter or template, the path from proof‑of‑concept to MVP is much shorter for the prospect’s team.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Guardrails: what &lt;em&gt;not&lt;/em&gt; to show
&lt;/h2&gt;

&lt;p&gt;Finally, a few things to consciously avoid in demos, especially when they’re recorded or public:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No confidential customer data.&lt;/strong&gt; Use synthetic or anonymized data that can’t be traced back to real people, companies, or contracts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No internal‑only metrics, roadmaps, or legal details.&lt;/strong&gt; If it’s not already public, it doesn’t belong in a public demo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No “black box” shortcuts.&lt;/strong&gt; If you can’t explain how something works in terms a developer would accept, it’s better to simplify than to hand‑wave.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These constraints are good discipline. They force you to rely on documented capabilities and well‑understood patterns which happens to be exactly what your audience wants to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;As demo engineers, we live in the space between &lt;strong&gt;aspiration&lt;/strong&gt; and &lt;strong&gt;implementation&lt;/strong&gt;. Our job isn’t to build the final product, it’s to prove that a real product could exist, on a realistic timeline, using tools the audience trusts.&lt;/p&gt;

&lt;p&gt;You don’t need a specific vendor or stack for that. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A realistic architecture your audience recognizes.&lt;/li&gt;
&lt;li&gt;A thoughtful content model and believable data.&lt;/li&gt;
&lt;li&gt;A workflow‑driven narrative that starts with a problem and ends with a live experience.&lt;/li&gt;
&lt;li&gt;A handoff that feels like a starting point, not a magic trick.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you treat your next demo as a small, honest product, instead of a disposable prototype, you’ll not only earn more trust in the room, you’ll also give the dev team something they can actually build on when the meeting ends.&lt;/p&gt;

</description>
      <category>demos</category>
      <category>softwaredevelopment</category>
      <category>careertips</category>
      <category>devrel</category>
    </item>
    <item>
      <title>What is React memo? How to improve React performance</title>
      <dc:creator>Hugo Naili</dc:creator>
      <pubDate>Tue, 28 Apr 2026 04:35:57 +0000</pubDate>
      <link>https://dev.to/hugonaili/what-is-react-memo-how-to-improve-react-performance-fk</link>
      <guid>https://dev.to/hugonaili/what-is-react-memo-how-to-improve-react-performance-fk</guid>
      <description>&lt;p&gt;React memo is a powerful feature that improves the performance of your React applications by letting you skip the re-rendering of components that haven't changed.&lt;/p&gt;

&lt;p&gt;This article explains how React memo works and how to use it. It also includes use cases and code examples that you can adapt for use in your own React code to make sure that your applications are as fast and efficient as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is React memo?
&lt;/h2&gt;

&lt;p&gt;Memoization is a programming technique that improves performance by caching the results of a function. Code that implements memoization checks the result of a function each time it is called to see if it can serve the cached result and avoid recomputation.&lt;/p&gt;

&lt;p&gt;In the context of React, this means storing the results of rendering a component to avoid excessive re-renders. &lt;a href="https://react.dev/reference/react/memo" rel="noopener noreferrer"&gt;React memo&lt;/a&gt; is a component that allows you to wrap React components and memoize them based on their properties (props). This means that components wrapped in a &lt;code&gt;memo&lt;/code&gt; will not be re-rendered if their properties have not changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How React memo works
&lt;/h2&gt;

&lt;p&gt;Typically in React, when the state is updated in a parent component, this will trigger a re-render of that component along with any of its child components, even if only some of them rely on the updated state. This can lead to poor performance, especially if some of those components make API calls or perform complex calculations.&lt;/p&gt;

&lt;p&gt;This is solved by using React memo: When you wrap one of your components with a &lt;code&gt;memo&lt;/code&gt; component, it will shallowly compare its current props to its previous ones, and if there is no change in the props, React will skip re-rendering that component and continue to use the existing result (as it was in the previous &lt;a href="https://www.freecodecamp.org/news/what-is-the-virtual-dom-in-react/" rel="noopener noreferrer"&gt;virtual DOM&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;For example, if you have a React parent component that displays the value of the U.S. dollar in different currencies (each currency conversion being in its own child component), each time the state of the parent component is updated with new currency data, every child component is re-drawn — even if the conversion rate hasn't changed. By wrapping each child component with &lt;code&gt;memo&lt;/code&gt;, only those where the calculated value has actually changed will be redrawn, improving performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shallow vs. deep comparison
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shallow comparison&lt;/strong&gt; – If a prop is a primitive (string or number), React memo will check if the new value is different from the old one. If a prop is an object or an array, React memo will only compare the memory reference; even if the contents are the same but the reference has changed, it will consider them different and trigger a re-render.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep comparison&lt;/strong&gt; – If a prop is complex, such as an array or object, comparison would require checking every nested value within to ensure all properties are equal to the old values. While this would provide an exact match, it’s computationally expensive and can be slower than the actual re-renders you are trying to prevent. Deep comparison should be avoided by using composition-based patterns to move the state closer to where it’s needed, minimizing the need for complex prop comparisons.&lt;/p&gt;

&lt;p&gt;The benefits of using React memo to optimize your components include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preventing unnecessary re-renders and avoiding redundant updates.&lt;/li&gt;
&lt;li&gt;Improving performance.&lt;/li&gt;
&lt;li&gt;Optimizing expensive and complex components.&lt;/li&gt;
&lt;li&gt;Enhancing the user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As memo is simple to implement by wrapping your existing React components, it is an effective way to improve the efficiency of your apps without significantly reworking them.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use React memo (demo)
&lt;/h2&gt;

&lt;p&gt;Now that you know what React memo is and how it works, let's take a look at some code and how you can use it in an application.&lt;/p&gt;

&lt;p&gt;In your React project, create a parent component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ChildComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./ChildComponent.jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ParentComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cardData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCardData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clicked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setClicked&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Card &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;

    &lt;span class="nf"&gt;setCardData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pushItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setClicked&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderWithoutMemo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderedComponents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChildComponent&lt;/span&gt;
          &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pushItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pushItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;clicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;renderedComponents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
          &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;boxSizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-box&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;flexWrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;renderWithoutMemo&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;ParentComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the component is initialized by creating some mock data, which will render out a list of child components. With 5,000 components, other optimization techniques could be used here (pagination, for example), but this is just to demonstrate a clearly noticeable performance lag. &lt;/p&gt;

&lt;p&gt;This component also includes some functionality that allows the user to click a child component from the list that will add its id to an array. This is checked later to decide if it has been clicked or not.&lt;/p&gt;

&lt;p&gt;Next, create a child component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ChildComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rendering - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;calculatePrimes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isPrime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;isPrime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;primeNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculatePrimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
        &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isClicked&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#f9f9f9&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px solid black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;primeNumbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;listStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prime&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prime&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;ChildComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just a simple card component with some code to simulate some sort of expensive computation in each list item.&lt;/p&gt;

&lt;p&gt;Now, if you run the application, you will be able to see a noticeable delay in performance when you click a card to change its color. If you open up the console window in your browser, you will also be able to see that each child component logs a message every time you click, showing that updating one component is triggering a re-render for all children.&lt;/p&gt;

&lt;p&gt;Now let's add the fix with React memo. Add the below code in &lt;code&gt;App.js&lt;/code&gt; above the &lt;code&gt;ParentComponent&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MemoizedChildComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;ChildComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isClicked&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a React memo component by wrapping the child in the &lt;code&gt;React.memo&lt;/code&gt; component. By default, &lt;code&gt;React.memo&lt;/code&gt; does a shallow comparison of props. This would normally be sufficient, but because the prop &lt;code&gt;isClicked&lt;/code&gt; is generated dynamically (by using &lt;code&gt;.some&lt;/code&gt; to generate a boolean), you have to pass a second argument to &lt;code&gt;React.memo&lt;/code&gt; with an equality check function, allowing you to customize the way properties are checked. This function opens up the possibility to check objects deeply.&lt;/p&gt;

&lt;p&gt;This is one of the common pitfalls with using React memo. The bottom line should be to either ensure that comparison props are simple values such as numbers or strings, or use a custom equality check for complex props.&lt;/p&gt;

&lt;p&gt;Now add the following function above the &lt;code&gt;renderWithoutMemo&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderWithMemo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderedComponents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MemoizedChildComponent&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pushItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pushItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;clicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;renderedComponents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the return statement, remove the current &lt;code&gt;renderwithoutMemo()&lt;/code&gt; and replace it with &lt;code&gt;renderWithMemo()&lt;/code&gt;. Now, if you refresh the application, you should see a notable improvement in the load speed when you click on a card. Also, in the console, you will only see logs from the cards you click on, showing that the other child components have been memoized. The only components being re-rendered now are the components whose props have changed.&lt;/p&gt;

&lt;p&gt;Here you can access a &lt;a href="https://tinyurl.com/4cjrscb9" rel="noopener noreferrer"&gt;working demo&lt;/a&gt; of the application where you can switch between &lt;code&gt;renderWithMemo()&lt;/code&gt; and &lt;code&gt;renderWithoutMemo()&lt;/code&gt; to see the performance lag.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use React memo
&lt;/h2&gt;

&lt;p&gt;It is considered best practice to use React memo in the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frequent prop changes:&lt;/strong&gt; If the props of a parent component change frequently but the output of a child component stays the same.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expensive rendering:&lt;/strong&gt; If you have some complex calculation going on inside a component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Large list of components:&lt;/strong&gt; If you have a large list of components, especially if the props are changing frequently in a parent component or you have expensive computation inside each child component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pure function components:&lt;/strong&gt; Components that render often and rely solely on the input props to determine their rendering output and have no internal state or side effects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If none of the above scenarios are true, React memo will have negligible benefits and may add unnecessary complexity to your application. To take one of the examples above, if you use React memo on a component that usually renders with different props, React will do two jobs; it will invoke the comparison function to determine whether the previous and next props are equal, and because the props comparison will always return false in this scenario, React will re-render the component anyway. So, you will get no performance benefits, and this will actually result in more overhead than benefit. &lt;/p&gt;

&lt;p&gt;You should use the &lt;a href="https://react.dev/reference/react/Profiler" rel="noopener noreferrer"&gt;profiler tool&lt;/a&gt; provided by React to identify any performance issues. The Profiler tool allows you to measure how often a component renders and how long these renders take, helping you determine if memoization would provide actual performance improvements. By profiling first, you can make informed decisions about when React memo is truly beneficial, avoiding needless optimizations.&lt;/p&gt;

&lt;p&gt;React provides a couple of other related performance optimization tools. While React memo focuses on optimizing whole component re-renders, these two are a little more granular as they require you to optimize specific parts of your components:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/useMemo" rel="noopener noreferrer"&gt;&lt;code&gt;useMemo()&lt;/code&gt;&lt;/a&gt;: In React, useMemo is a hook that can wrap computationally heavy functions to memoize the result, so if the function is called again with the same arguments, the result doesn't need to be recalculated each time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/useCallback" rel="noopener noreferrer"&gt;&lt;code&gt;useCallback()&lt;/code&gt;&lt;/a&gt;: This hook can be used to wrap a function to memoize its reference. It takes a set of dependencies that determine whether the function should be redefined; if the dependencies remain the same, the memoized function can be reused. It's used to prevent unnecessary re-creation of functions that are passed down as props.&lt;/p&gt;

&lt;p&gt;Performance matters in React applications&lt;br&gt;
According to the &lt;a href="https://lawsofux.com/doherty-threshold/" rel="noopener noreferrer"&gt;Doherty threshold&lt;/a&gt;, applications that respond in 400 ms or under keep a user's attention and increase engagement, and anything over that causes frustration and may result in users leaving your application altogether.&lt;/p&gt;

&lt;p&gt;As your React application scales and grows in complexity, you may find that it starts to slow down as you add more functionality and complex components. This is why it is advisable to employ optimization strategies such as memoization with React memo, pagination, or lazy loading from the beginning of your project, so that it always performs as well as possible.&lt;/p&gt;

</description>
      <category>react</category>
      <category>performance</category>
      <category>hooks</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
