﻿<?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: Chocoscoding - Oyeti Timileyin</title>
    <description>The latest articles on DEV Community by Chocoscoding - Oyeti Timileyin (@chocoscoding).</description>
    <link>https://dev.to/chocoscoding</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F657909%2F8642b77d-5234-44db-996f-aaa8b6353e6a.jpeg</url>
      <title>DEV Community: Chocoscoding - Oyeti Timileyin</title>
      <link>https://dev.to/chocoscoding</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chocoscoding"/>
    <language>en</language>
    <item>
      <title>TypeScript Patterns for Environment Variables</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Tue, 16 Jun 2026 00:22:00 +0000</pubDate>
      <link>https://dev.to/chocoscoding/typescript-patterns-for-environment-variables-5eeg</link>
      <guid>https://dev.to/chocoscoding/typescript-patterns-for-environment-variables-5eeg</guid>
      <description>&lt;p&gt;Yesterday, as I was working on a CORS configuration, AI generated a block of code for me:&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;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRONTEND_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADMIN_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001&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="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was wondering... why use &lt;code&gt;.filter(Boolean)&lt;/code&gt; here? 🤔 The fallbacks already guarantee strings.&lt;/p&gt;

&lt;p&gt;So I hovered on the variable. The type definition read:&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;allowedOrigins&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine. Made sense. But then I got curious. What if I removed the hardcoded fallbacks?&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;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRONTEND_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADMIN_URL&lt;/span&gt;&lt;span class="p"&gt;,&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="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My type definition changed to:&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;allowedOrigins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;&lt;em&gt;I was shocked.&lt;/em&gt; I just filtered the array. How can TypeScript still think there's an &lt;code&gt;undefined&lt;/code&gt; in there?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  First: What Does &lt;code&gt;.filter(Boolean)&lt;/code&gt; Even Do?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Boolean&lt;/code&gt; used as a filter function removes any falsy value from an array:&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="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;undefined&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;NaN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So:&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="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://app.com&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="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Result: ["https://app.com"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At runtime, this works exactly as you'd expect. No &lt;code&gt;undefined&lt;/code&gt; survives. So why does TypeScript disagree? 🤷‍♀️&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Answer: TypeScript Doesn't Run Your Code
&lt;/h2&gt;

&lt;p&gt;TypeScript is a transpiler. It doesn't execute &lt;code&gt;.filter(Boolean)&lt;/code&gt; -&amp;gt; it only looks at types.&lt;/p&gt;

&lt;p&gt;When it sees this:&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="nx"&gt;array&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="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It knows the callback returns a &lt;code&gt;boolean&lt;/code&gt;. But it doesn't know what that &lt;em&gt;means&lt;/em&gt; for the type of the elements that survive. It can't infer "if &lt;code&gt;Boolean(x)&lt;/code&gt; is true, then &lt;code&gt;x&lt;/code&gt; must be a string." So the &lt;code&gt;undefined&lt;/code&gt; stays in the type — even though it'll never actually be there at runtime.&lt;/p&gt;

&lt;p&gt;That's the gap: your runtime behavior is correct, but your types are lying.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix: Type Predicates
&lt;/h2&gt;

&lt;p&gt;TypeScript lets you close that gap with a &lt;strong&gt;type predicate&lt;/strong&gt;, a way of explicitly telling the compiler what a filter function guarantees:&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;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRONTEND_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADMIN_URL&lt;/span&gt;&lt;span class="p"&gt;,&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;origin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Type: string[] ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;origin is string&lt;/code&gt; part is the predicate. It's a promise to the compiler: &lt;em&gt;"if this function returns &lt;code&gt;true&lt;/code&gt;, the value is definitely a string."&lt;/em&gt; TypeScript trusts that and narrows the type accordingly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Reusable Helper
&lt;/h2&gt;

&lt;p&gt;If you're doing this pattern often across a codebase, pull it into a small utility:&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;isDefined&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;T&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;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&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:&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;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRONTEND_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADMIN_URL&lt;/span&gt;&lt;span class="p"&gt;,&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;isDefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Type: string[] ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reusable, self-documenting, and sexy 😍. I personally prefer this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Back to the Original Code
&lt;/h2&gt;

&lt;p&gt;So why did the AI-generated version with the &lt;code&gt;||&lt;/code&gt; fallbacks give &lt;code&gt;string[]&lt;/code&gt; without needing a predicate?&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;allowedOrigins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRONTEND_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ADMIN_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001&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="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;process.env.X || "fallback"&lt;/code&gt; always evaluates to a &lt;code&gt;string&lt;/code&gt;. The fallback string covers the &lt;code&gt;undefined&lt;/code&gt; case, so TypeScript already knows every element is a &lt;code&gt;string&lt;/code&gt; before the filter runs. The &lt;code&gt;.filter(Boolean)&lt;/code&gt; there is just a defensive move... useful if someone later adds an entry without a fallback, but not needed for type correctness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;.filter(Boolean)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type def: &lt;code&gt;(string | undefined)[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use when: You don't care about the resulting type.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;.filter((x): x is string =&amp;gt; Boolean(x))&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type def: &lt;code&gt;string[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use when: Inline, one-off.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;.filter(isDefined)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type def: &lt;code&gt;string[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use when: Reusable across a codebase.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;process.env.X || "fallback"&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type def: &lt;code&gt;string&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use when: You want a guaranteed default.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The lesson: &lt;code&gt;filter(Boolean)&lt;/code&gt; is a runtime thing that TypeScript treats as a black box. When you need your types actually to reflect what's in the array, reach for a type predicate. Small change, honest types.&lt;/p&gt;

&lt;p&gt;Thanks for reading 👍&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AI subsidy removed... Is the bubble about to burst?</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Fri, 12 Jun 2026 14:16:32 +0000</pubDate>
      <link>https://dev.to/chocoscoding/ai-subsidy-removed-is-the-bubble-about-to-burst-2omj</link>
      <guid>https://dev.to/chocoscoding/ai-subsidy-removed-is-the-bubble-about-to-burst-2omj</guid>
      <description>&lt;p&gt;&lt;strong&gt;After 2 years of being constantly told that AI would take jobs, replace people, and disrupt markets... the narrative is finally shifting.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Companies are now paying significantly more for AI just to handle routine tasks. Developers aren't immune either; Claude Pro plans are hitting weekly limits faster than ever on prompts that used to cost very little. GitHub Copilot has also become considerably more expensive following its change to a new billing model &lt;em&gt;(Usage is now measured in AI credits — 1 credit equals $0.01 USD)&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  But why did it get so expensive all of a sudden?
&lt;/h2&gt;

&lt;p&gt;AI runs on serious hardware. The way it uses 10 .md instruction files and fixes your bug in a single prompt; that isn't cheap to run. The compute costs behind every interaction are real and significant.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So why were we paying so little for so long?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI companies needed people to use the product, get familiar with it, and let it become a core part of their workflow. Telling people to pay $100 upfront for unproven software was never going to work. So they did something smarter:&lt;/p&gt;

&lt;p&gt;Step A: Raise substantial funding&lt;br&gt;
Step B: Use it to subsidize the cost of AI, making it cheap or free&lt;br&gt;
Step C: Accelerate adoption and build dependency&lt;br&gt;
Step D: Roll pricing back to levels that actually sustain a business&lt;/p&gt;

&lt;p&gt;It's a classic land-and-expand play, and it worked. But now we're in Step D.&lt;/p&gt;

&lt;p&gt;So does AI become a premium tool only the privileged can fully use?&lt;/p&gt;

&lt;p&gt;That question is becoming harder to dismiss. Even major players are feeling the pressure.&lt;/p&gt;

&lt;p&gt;Bryan Catanzaro, Vice President of Applied Deep Learning at Nvidia, suggested that AI adoption isn't actually reducing labor costs and, in some cases, may exceed the cost of the employees it was meant to replace. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"For my team, the cost of compute is far beyond the costs of the employees," he told Axios.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Microsoft has reportedly begun canceling licenses for its engineers to use Anthropic's Claude, citing high costs — raising serious questions about the long-term economics of enterprise AI adoption.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And then there's what Sam Altman said during a virtual interview at a Commonwealth Bank of Australia conference:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I don't think we're going to have the kind of jobs apocalypse that some of the companies in our space advocate or talk about."&lt;br&gt;
"I thought there would have been more impact on entry-level white-collar jobs being eliminated by now than has actually happened. I now think I understand more about why it hasn't, and I'm obviously grateful, but that is an area where my intuitions were just off."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Altman went on to say that the human dimension of work is harder to replace than anticipated. That people genuinely care about interacting with each other, not just getting tasks done.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We really do care about our interactions with people," he added — which, he said, "updated me to thinking that the jobs picture is likely to be very different than we thought."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;The CEO of Linear put it well on X:&lt;/em&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%2Fkk3aryg0fh5lvplidbqd.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%2Fkk3aryg0fh5lvplidbqd.png" alt="CEO of Linear on X" width="750" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happens next
&lt;/h2&gt;

&lt;p&gt;My honest opinion: costs keep rising as companies don't want to fall into massive loss, and spending tokens carelessly becomes a real consideration. Developers will need to be more deliberate and write more of their own code again 😮‍💨.&lt;/p&gt;

&lt;p&gt;Companies will start hiring again. But not for the roles that AI has genuinely absorbed: basic, repetitive, well-defined tasks.&lt;/p&gt;

&lt;p&gt;The demand will be for people who can create, build, and maintain processes that produce results efficiently, with or without AI. Architect-level, senior, and even solid mid-level roles. People who think in systems, not just syntax.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The AI-replaces-everyone story was always too simple.&lt;/em&gt; What's emerging is more nuanced: AI compresses the value of shallow work and amplifies the value of deep work. If you can do the latter, you're more relevant than ever.&lt;/p&gt;

&lt;p&gt;Thanks for reading 👍&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Why Sell Software If Anyone Can Make It?</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Mon, 04 May 2026 13:30:04 +0000</pubDate>
      <link>https://dev.to/chocoscoding/why-sell-software-if-anyone-can-make-it-2h7l</link>
      <guid>https://dev.to/chocoscoding/why-sell-software-if-anyone-can-make-it-2h7l</guid>
      <description>&lt;p&gt;&lt;em&gt;Making yogurt at home isn't hard&lt;/em&gt;. You can control the sugar, the fat, add any flavour you want. Free from the tyranny of Big Yogurt!&lt;/p&gt;

&lt;p&gt;Yet somehow, &lt;strong&gt;Danone&lt;/strong&gt; is still doing fine.&lt;/p&gt;

&lt;p&gt;Same goes for &lt;em&gt;home-brewed beer&lt;/em&gt;, &lt;em&gt;homemade bread&lt;/em&gt;, &lt;em&gt;3D printing&lt;/em&gt;. All great hobbies. All more accessible than ever. None have actually disrupted their industries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here's why:
&lt;/h2&gt;

&lt;p&gt;Better tools raise the floor and the ceiling. The hobbyist gets better, but so does the dedicated team whose entire job is perfecting that one product.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The gap doesn't close. It just moves up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Software is the same story.&lt;/strong&gt;&lt;br&gt;
Yes, a non-technical founder can vibe-code an MVP today. But that MVP still hits a wall when real users show up, payments need to work, and Safari breaks something. I've literally fixed these apps for a living. The demand for "please save my AI-built app" is very real.&lt;/p&gt;

&lt;p&gt;Most people don't want to build their own software anyway. They want the problem solved, the thing to work, and support when it breaks.&lt;br&gt;
AI doesn't change that deal. It just changes what's possible on both sides of it.&lt;/p&gt;

&lt;p&gt;So if you're thinking about building and selling software in 2026... don't let the boogeyman of hobbyists vibe-coding a replacement scare you out of it.&lt;/p&gt;

&lt;p&gt;Share your thoughts and what you are building today.&lt;/p&gt;

&lt;p&gt;Ps: If you are stuck with your App/Website, Hit me up or Contact on &lt;a href="https://www.fiverr.com/s/o81yGRX" rel="noopener noreferrer"&gt;Fiverr&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>Built a 5k usd MRR app with AI but still needed a developer</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Tue, 21 Apr 2026 02:51:12 +0000</pubDate>
      <link>https://dev.to/chocoscoding/built-a-5k-usd-mrr-app-with-ai-but-still-needed-a-developer-2k8p</link>
      <guid>https://dev.to/chocoscoding/built-a-5k-usd-mrr-app-with-ai-but-still-needed-a-developer-2k8p</guid>
      <description>&lt;p&gt;You see it everywhere you turn:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built this using just AI and im making 10K USD MRR"&lt;/p&gt;

&lt;p&gt;"Just got funded 1 million dollars at 100 million USD valuation for my app i built with AI"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, I see it too... Initially, I was always thinking.&lt;br&gt;
Damn! We(Devs) are so cooked 😬,&lt;br&gt;
And more importantly… what about the next generation of devs?&lt;br&gt;
Are they even going to want to enter this field anymore?&lt;/p&gt;

&lt;p&gt;Questions that cast shadows of doubt about "Developers/Programmers relevance" would pop up.&lt;/p&gt;

&lt;p&gt;Then something changed....&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Bug Fixing in Freelancing
&lt;/h2&gt;

&lt;p&gt;I went to fiverr and saw a trend... AI services were hot there.&lt;br&gt;
But the ones that piqued my interest was: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI-bug fixing, deployment and mvps&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You see, AI still had to use the current architectures and systems that were already created.&lt;br&gt;
But the average vibe-coding CEO didn't understand what the hell CI/CD was, or why their feature won't work on Safari, or how to stop bottleneck issues, or why GCP is returning an error.&lt;/p&gt;

&lt;p&gt;Lovable, Bolt, Replit etc Their AI would always give them hopes even though its wrong or making things worse.&lt;/p&gt;

&lt;p&gt;The fault isn't totally on the AI though. The startup founders who want to make their own 10K/month revenue app don't know how to best guide the AI. Garbage in, garbage out... except the garbage looks really confident and ships fast.&lt;/p&gt;

&lt;p&gt;For simple-to-medium stuff? &lt;em&gt;It works.&lt;/em&gt;&lt;br&gt;
Missing semicolon, broken API call, quick UI tweak, adding automation flows... AI nails those&lt;/p&gt;

&lt;p&gt;But here's what's also real:&lt;br&gt;
&lt;strong&gt;Most of those AI-built service eventually ends up in front of a human developer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every single one of those AI codebases hits a wall. And when it does, someone posts on Reddit:&lt;/p&gt;

&lt;p&gt;"Looking for a senior dev to untangle this mess. Will pay well."&lt;/p&gt;

&lt;p&gt;The irony is beautiful. AI is generating a new category of freelance work: cleaning up after itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 Why People Still Need You
&lt;/h2&gt;

&lt;p&gt;Here's the pattern repeating across the freelance market right now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Founder uses AI to build MVP&lt;/li&gt;
&lt;li&gt;MVP grows, gets complex, accumulates technical debt&lt;/li&gt;
&lt;li&gt;AI starts hallucinating fixes that break other things&lt;/li&gt;
&lt;li&gt;Founder is confused, frustrated, and losing money&lt;/li&gt;
&lt;li&gt;Founder hires a developer 🙂‍↕️
And that's not the only thing keeping developers essential:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Context is everything...&lt;br&gt;
&lt;em&gt;AI doesn't know your client's 8-year-old legacy codebase.&lt;/em&gt;&lt;br&gt;
or&lt;br&gt;
&lt;em&gt;It doesn't know that the "bug" in the payment module is actually an intentional workaround nobody documented properly.&lt;/em&gt; 😂&lt;/p&gt;

&lt;p&gt;Also, the stakes get real fast too...&lt;br&gt;
&lt;strong&gt;Bug in production. Money bleeding. CEO panicking.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nobody's waiting on a prompt chain. &lt;em&gt;They're calling a developer or someone technical ASAP!&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Debugging a function is one thing.&lt;br&gt;
Designing the system, making tradeoffs, scaling it… that’s experience, which is highly relevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠️ The Bubble We May See
&lt;/h2&gt;

&lt;p&gt;Now here's the part that genuinely worries me... and I don't see enough people connecting these dots.&lt;/p&gt;

&lt;p&gt;The job shortage isn't just hurting developers today. It's quietly killing the next generation of developers before they even start.&lt;br&gt;
Here's the thing...&lt;/p&gt;

&lt;p&gt;Junior devs have always learned by getting hired. Working under seniors. Making mistakes in low stakes environments. Getting roasted in code review until they got good.&lt;/p&gt;

&lt;p&gt;That pipeline is breaking.&lt;/p&gt;

&lt;p&gt;Companies are cutting junior roles first.&lt;br&gt;
Why hire a junior when AI can handle the boilerplate?&lt;/p&gt;

&lt;p&gt;From a business perspective… it makes total sense.&lt;br&gt;
But think about it for a second:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If no one hires juniors…&lt;br&gt;
where do seniors come from?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The people entering the industry now are learning in a vacuum. Or not entering at all. Bootcamp enrollment is down. Too much reliance on AI without understanding concepts very well. CS grads are pivoting out. The message young people are getting is clear...&lt;/p&gt;

&lt;p&gt;so they think: "There are no jobs, so why bother? 🤷" &lt;/p&gt;

&lt;p&gt;Advice: &lt;em&gt;Please bother. Give it a shot... me and my peers won't be here forever. You are the future.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌱 So Where Does This Leave You?
&lt;/h2&gt;

&lt;p&gt;If you're a developer right now: employed, freelancing, or searching. Here's the real talk:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short term:&lt;/strong&gt; It's rough. Adapt your positioning. There's still space here... for specialists, for generalists, for everyone in between. &lt;br&gt;
That &lt;em&gt;PostgREST&lt;/em&gt; bottleneck issue you fixed that one time? Someone today is tearing their hair out over the exact same thing.&lt;/p&gt;

&lt;p&gt;No knowledge is lost 😉.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Medium term:&lt;/strong&gt; Demand is growing for developers who understand AI-generated code. Who can audit it, extend it, deploy it properly. That's a real thing now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long term:&lt;/strong&gt; Niche down. Get so deep on your concepts that you're not just using AI... you're directing it. The developers who understand the fundamentals well enough to drive AI-aided development? They're going to produce results nobody else can replicate.&lt;/p&gt;

&lt;p&gt;And if the pipeline breaks the way I think it is... those developers won't just be valuable. &lt;strong&gt;&lt;em&gt;They'll be rare.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The startup founder still needs someone to help when the app has been down since yesterday evening, users are churning, and the AI says it's done while the feature is still not working.&lt;/p&gt;

&lt;p&gt;So guys... &lt;strong&gt;&lt;em&gt;Stay in the game.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
The future isn’t fewer developers. It’s fewer average ones...👋👋&lt;/p&gt;

&lt;p&gt;You can also check out my fiverr gig on &lt;a href="https://www.fiverr.com/s/ZmVXQ1k" rel="noopener noreferrer"&gt;AI app fixing and development&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>discuss</category>
      <category>saas</category>
    </item>
    <item>
      <title>Stop the `data.data` Madness: Building a Custom Axios Client in TypeScript</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Fri, 05 Dec 2025 17:15:41 +0000</pubDate>
      <link>https://dev.to/chocoscoding/stop-the-datadata-madness-building-a-custom-axios-client-in-typescript-36p6</link>
      <guid>https://dev.to/chocoscoding/stop-the-datadata-madness-building-a-custom-axios-client-in-typescript-36p6</guid>
      <description>&lt;p&gt;I was recently working on a project where the backend team decided (wisely) to wrap every API response in a standard envelope:&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;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&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;"meta"&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;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&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;p&gt;On the backend, this is clean and consistent. I actually love it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But in React components, it turns the code into a repetitive nightmare.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just look at this:&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="c1"&gt;// 🤮 The Issue&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="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Double data? Really?&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="nx"&gt;response&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;data&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;message&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;data&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If I had to type &lt;code&gt;response.data.data&lt;/code&gt; one more time, I was going to scream.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are a frontend developer working with a structured backend, you know this struggle.&lt;/p&gt;

&lt;p&gt;Today, let’s fix this. We are going to build a &lt;strong&gt;Custom API Client&lt;/strong&gt; in TypeScript that unwraps this envelope automatically, handles types safely, and keeps your component logic clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Goal
&lt;/h3&gt;

&lt;p&gt;We want to transform Axios so that when we call &lt;code&gt;get&lt;/code&gt;, we receive the inner data immediately at the top level, fully typed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target Usage:&lt;/strong&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="c1"&gt;// 😍 The New Way&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;data&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;meta&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;apiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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="s1"&gt;/users/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// TypeScript knows 'data' is a User!&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;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="c1"&gt;// ✅ Access the server message:&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="s2"&gt;`Alert: &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;message&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="c1"&gt;// ✅ Meta data {page: 1, totalPages: 6, totalProducts: 120}&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="s2"&gt;`Current page: &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;meta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;page&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 1: Define the Backend Contract
&lt;/h3&gt;

&lt;p&gt;First, we need to tell TypeScript what the "Raw" response looks like coming from the server.&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="c1"&gt;// The shape of the raw JSON from the server&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ApiResponse&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;message&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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The shape when pagination metadata is involved&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ApiResponseWithMeta&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;message&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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;M&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;h3&gt;
  
  
  Step 2: The "Typed" Response
&lt;/h3&gt;

&lt;p&gt;Next, we define what we &lt;em&gt;want&lt;/em&gt; our frontend to receive. We are going to "hoist" the &lt;code&gt;message&lt;/code&gt; and &lt;code&gt;meta&lt;/code&gt; fields up, so they sit right next to our actual data, removing that annoying nesting.&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;AxiosResponse&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;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// We omit the standard 'data' property and replace it with our own typed version&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TypedAxiosResponse&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AxiosResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The actual resource (User, Product, etc.)&lt;/span&gt;
  &lt;span class="nl"&gt;message&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="c1"&gt;// Hoisted from the nested object&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// A version for paginated responses&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TypedAxiosResponseWithMeta&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;TypedAxiosResponse&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;meta&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;M&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;h3&gt;
  
  
  Step 3: The Magic Wrapper
&lt;/h3&gt;

&lt;p&gt;Instead of using the raw &lt;code&gt;axios&lt;/code&gt; instance directly in our components, we create an &lt;code&gt;apiClient&lt;/code&gt; object. This acts as a &lt;strong&gt;Facade&lt;/strong&gt;. It calls Axios, intercepts the result, and unwraps it before returning it to you.&lt;/p&gt;

&lt;p&gt;Here is the logic:&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="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&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;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Create the base instance with your interceptors (Auth, Logging, etc.)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseApiClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. The Custom Client&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;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="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&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;TypedAxiosResponse&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;&amp;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="c1"&gt;// Call the raw axios instance&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="nx"&gt;baseApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApiResponse&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;&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="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ✨ THE MAGIC: Remap response.data.data -&amp;gt; response.data&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&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;data&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="c1"&gt;// Unwrapping happens here&lt;/span&gt;
      &lt;span class="na"&gt;message&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;data&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;TypedAxiosResponse&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="c1"&gt;// You can repeat this pattern for post, put, delete...&lt;/span&gt;
  &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&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;TypedAxiosResponse&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;&amp;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;response&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;baseApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApiResponse&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;&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&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;data&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="na"&gt;message&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;data&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;TypedAxiosResponse&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Handling Pagination (The &lt;code&gt;meta&lt;/code&gt; Field)
&lt;/h3&gt;

&lt;p&gt;Sometimes you need that extra metadata (page numbers, total counts). Let's add a specific method for that so we don't clutter standard calls.&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="nx"&gt;getWithMeta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&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;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&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;TypedAxiosResponseWithMeta&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="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;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;response&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;baseApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApiResponseWithMeta&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="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nx"&gt;config&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&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;data&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="na"&gt;message&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;data&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="na"&gt;meta&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Now easily accessible!&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;TypedAxiosResponseWithMeta&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="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;M&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;Now, look at how clean your service files or components become.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&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;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/users/&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Hope you remember to check if res.data.data exists!&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&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;data&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;After:&lt;/strong&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="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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="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="c1"&gt;// Typescript infers 'data' is User, and 'message' is string&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;data&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;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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="s2"&gt;`/users/&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&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="c1"&gt;// "User retrieved successfully"&lt;/span&gt;
  &lt;span class="k"&gt;return&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bonus: Centralized Error Handling
&lt;/h3&gt;

&lt;p&gt;Because we still use &lt;code&gt;baseApiClient&lt;/code&gt; underneath, we can attach interceptors to handle 401s (Unauthorized) or 500s globally.&lt;/p&gt;

&lt;p&gt;If your token expires, your base client can catch it, attempt a refresh, or redirect to login via &lt;code&gt;next-auth&lt;/code&gt; before your component even knows something went wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Don't let your backend structure dictate your frontend messiness. By creating a lightweight wrapper around Axios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; You stop typing &lt;code&gt;.data.data&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; You get perfect TypeScript autocomplete.&lt;/li&gt;
&lt;li&gt; You separate your HTTP logic from your UI logic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>development</category>
      <category>programming</category>
      <category>api</category>
    </item>
    <item>
      <title>Sitemap couldn't fetch in Google Search Console - fix</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Wed, 01 Jan 2025 13:27:12 +0000</pubDate>
      <link>https://dev.to/chocoscoding/sitemap-couldnt-fetch-in-google-search-console-fix-4983</link>
      <guid>https://dev.to/chocoscoding/sitemap-couldnt-fetch-in-google-search-console-fix-4983</guid>
      <description>&lt;p&gt;To set up your site to be indexed by Google Search, you need to have a &lt;code&gt;robots.txt&lt;/code&gt; file and a &lt;code&gt;sitemap.xml&lt;/code&gt; file in your site.&lt;/p&gt;

&lt;p&gt;Here’s how I set up my own sitemap and robots file using Next.js. My solution takes TypeScript files and converts them into &lt;code&gt;.txt&lt;/code&gt; and &lt;code&gt;.xml&lt;/code&gt; files, which are then placed in the public directory of the site.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;robot.ts&lt;/code&gt;&lt;br&gt;
This is the code for my robots.txt file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
    },
    sitemap: "https://www.thook.xyz/sitemap.xml",
    host: "https://www.thook.xyz",
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sitemap.ts&lt;/code&gt;&lt;br&gt;
Below is the code for generating my sitemap.xml file dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  const routes: MetadataRoute.Sitemap = [
    {
      url: "",
      changeFrequency: "monthly",
      priority: 1,
    },
    {
      url: "/search",
      changeFrequency: "monthly",
      priority: 0.5,
    },
  ];

  return routes.map(({ url, ...rest }) =&amp;gt; ({
    ...rest,
    url: `https://thook.xyz${url}`,
    lastModified: new Date(),
  }));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Problem 🤔
&lt;/h2&gt;

&lt;p&gt;While my &lt;code&gt;robots.txt&lt;/code&gt; worked flawlessly, my &lt;code&gt;sitemap.xml&lt;/code&gt; kept returning an error:&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%2Fu5bbedum9hoa5ktyjiiu.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%2Fu5bbedum9hoa5ktyjiiu.png" alt="sitemap unsuccessful" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seemed like Google Search Console had cached an old version of my sitemap, and nothing I did seemed to fix the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution 🚀
&lt;/h2&gt;

&lt;p&gt;To work around this, I created a new sitemap2.xml file and placed it in the public directory of my Next.js application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;https://thook.xyz/&amp;lt;/loc&amp;gt;
        &amp;lt;lastmod&amp;gt;2025-01-01T11:39:05.531Z&amp;lt;/lastmod&amp;gt;
        &amp;lt;changefreq&amp;gt;yearly&amp;lt;/changefreq&amp;gt;
        &amp;lt;priority&amp;gt;1&amp;lt;/priority&amp;gt;
        &amp;lt;xhtml:link rel="home" href="https://thook.xyz/" /&amp;gt;
    &amp;lt;/url&amp;gt;
    &amp;lt;url&amp;gt;
        &amp;lt;loc&amp;gt;https://thook.xyz/search&amp;lt;/loc&amp;gt;
        &amp;lt;lastmod&amp;gt;2025-01-01T11:39:05.531Z&amp;lt;/lastmod&amp;gt;
        &amp;lt;changefreq&amp;gt;monthly&amp;lt;/changefreq&amp;gt;
        &amp;lt;priority&amp;gt;0.8&amp;lt;/priority&amp;gt;
        &amp;lt;xhtml:link rel="search" href="https://thook.xyz/search" /&amp;gt;
    &amp;lt;/url&amp;gt;
&amp;lt;/urlset&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, Booom!💥.&lt;br&gt;
Jan 1st problem solved ✅.&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%2F4w6o4thzzl0ka8dw7fqc.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%2F4w6o4thzzl0ka8dw7fqc.png" alt="sitemap successful" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned 📚
&lt;/h2&gt;

&lt;p&gt;Here’s what I learned about using Google Search Console:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be patient: Google Search Console can take time to crawl and update your site. Don’t panic.&lt;/li&gt;
&lt;li&gt;Try a fresh name: If you’re facing persistent errors, create a new sitemap with a different name that Google hasn’t cached yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>google</category>
      <category>react</category>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>Download Video from s3 with Cloudfront, nodejs and react</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Sun, 22 Dec 2024 12:07:33 +0000</pubDate>
      <link>https://dev.to/chocoscoding/download-video-from-s3-with-cloudfront-nodejs-and-react-15he</link>
      <guid>https://dev.to/chocoscoding/download-video-from-s3-with-cloudfront-nodejs-and-react-15he</guid>
      <description>&lt;p&gt;I never realized downloading a file on a button click could be such a headache, but here we are. After some trial and error, I did what we do best as developers—find solutions.&lt;/p&gt;

&lt;p&gt;Here’s the situation:&lt;br&gt;
I was using S3 and CloudFront for video file delivery. The videos were encrypted and access-restricted on the backend to ensure no one could directly grab them from my S3 bucket. Users had the ability to watch and download videos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Attempt 1: Basic Download Logic
&lt;/h2&gt;

&lt;p&gt;Initially, I tried the typical approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleDownload = () =&amp;gt; {
    const link = document.createElement("a");
    link.href = videoUrl;
    link.download = `${title || "video"}-thook.mp4`; // Provide a default filename if `title` is unavailable.
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link); // Cleanup after the download is triggered
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked… sort of. Instead of downloading, it redirected to another page and started playing the video.&lt;/p&gt;

&lt;p&gt;The culprit? I had set &lt;code&gt;ContentType&lt;/code&gt; during the S3 upload process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const param = {  
  Bucket: process.env.AWS_S3_BUCKET_NAME,  
  Key: `${directory}/${uuid()}-${file.originalname}`,  
  Body: file.buffer,  
  // ContentType: file.mimetype ❌ (Removed this)  
};  

await s3.upload(param).promise();  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After removing the &lt;code&gt;ContentType&lt;/code&gt; setting, files finally started downloading correctly on desktops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 2: Mobile Safari and Other Browser Issues
&lt;/h2&gt;

&lt;p&gt;The next problem? Safari on mobile devices and some other browsers still insisted on opening the video instead of downloading it.&lt;/p&gt;

&lt;p&gt;To fix this, I decided to stream the video from the backend using Node.js and set appropriate headers to force downloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from "axios";
const downloadWithSignedURL = async (req: Request, res: Response) =&amp;gt; {
  const signedUrl = req.query.signedUrl as string;
  const filename = (req.query.filename as string) || "video.mp4";

  if (!signedUrl) {
    return res.status(400).send("Signed URL is required.");
  }

  try {
    // Fetch the video stream using axios
    const response = await axios.get(signedUrl, {
      responseType: "stream",
    });

    if (response.status === 200) {
      // Set headers to force download
      res.setHeader("Content-Disposition", `attachment; filename="${filename}-THOOK.mp4"`);
      res.setHeader("Content-Type", "video/mp4");

      // Pipe the video stream to the client
      response.data.pipe(res);
    } else {
      res.status(response.status || 500).send("Failed to fetch video.");
    }
  } catch (error) {
    console.error("Error handling download:", error);
    res.status(500).send("Failed to handle download.");
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//route.ts
...
router.get("/downloadVideo", DownloadController.downloadWithSignedURL);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the frontend, I adjusted the logic to interact with this backend route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//in react 

const handleDownload = () =&amp;gt; {  
  const downloadUrl = `${API_ROUTE}/downloadVideo?signedUrl=${encodeURIComponent(url)}&amp;amp;filename=${encodeURIComponent(name || "video.mp4")}`;  
  window.open(downloadUrl, "_blank"); 
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Solution: Seamless Download Without a New Tab
&lt;/h2&gt;

&lt;p&gt;To improve user experience, I modified the logic to directly trigger downloads without opening a new tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleDownload = () =&amp;gt; {  
  if (!url) {  
    alert("Please provide the signed URL.");  
    return;  
  }  
  try {  
    const downloadUrl = `${API_ROUTE}/downloadVideo?signedUrl=${encodeURIComponent(url)}&amp;amp;filename=${encodeURIComponent(name || "video.mp4")}`;  

    const link = document.createElement("a");  
    link.href = downloadUrl;  
    link.setAttribute("download", name || "video.mp4");  
    document.body.appendChild(link);  
    link.click();  
    link.remove();  
  } catch (error) {  
    console.error("Download error:", error);  
  }  
};  

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

&lt;/div&gt;



&lt;p&gt;And voilà! The download now starts immediately after clicking the button, with no interruptions.&lt;/p&gt;

&lt;p&gt;So that is how I created the download feature you here:&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%2Fy8p935dqf53e52ppmj82.gif" 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%2Fy8p935dqf53e52ppmj82.gif" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Side Notes
&lt;/h2&gt;

&lt;p&gt;Here are a few key insights from the process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;S3 ContentType Issues: Setting &lt;code&gt;ContentType&lt;/code&gt; caused files always be in the specified format instead of downloading. Removing it fixed desktop downloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browser Compatibility: Safari and some browsers required backend streaming with forced download headers for consistency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better UX: Dynamically creating an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element allowed downloads without opening new tabs, creating a smoother user experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading 🙇‍♂️.&lt;/p&gt;

</description>
      <category>react</category>
      <category>aws</category>
      <category>s3</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Perfectly Qualified Yet Rejected? Here’s Why It Happens and What to Change</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Sun, 27 Oct 2024 22:34:06 +0000</pubDate>
      <link>https://dev.to/chocoscoding/perfectly-qualified-yet-rejected-heres-why-it-happens-and-what-to-change-4g6b</link>
      <guid>https://dev.to/chocoscoding/perfectly-qualified-yet-rejected-heres-why-it-happens-and-what-to-change-4g6b</guid>
      <description>&lt;p&gt;It’s a common &lt;strong&gt;frustration&lt;/strong&gt; for many job seekers: You’ve tailored your resume, crafted a great cover letter, and checked all the qualification boxes, yet you’re still facing rejection—or worse, not hearing back at all. If this sounds familiar, know that you’re not alone, and the reasons behind these rejections are often more complex than you might think.&lt;br&gt;
In this post, we’ll explore some &lt;strong&gt;hidden challenges&lt;/strong&gt; job seekers face today and offer actionable tips to help you overcome them.&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%2Fzyoh7incnvgf6nyma1pv.jpg" 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%2Fzyoh7incnvgf6nyma1pv.jpg" alt="job interview start image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let's look at some common &lt;strong&gt;scenarios&lt;/strong&gt; where highly qualified candidates still face &lt;strong&gt;rejection&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Growth Facade”
&lt;/h2&gt;

&lt;p&gt;Many companies post jobs to give an impression of rapid growth and expansion, even if they do not intend to fill the roles. This tactic sometimes used to boost company image or investor interest, can lead job seekers to waste time on positions that aren’t truly hiring.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What to Do&lt;/em&gt;: If you spot repeated job postings from the same company over time, it might be best to save your time and look elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remote isn't that straightforward
&lt;/h2&gt;

&lt;p&gt;The term “Remote” has become a powerful draw for job seekers, but it doesn’t always mean “Remote Worldwide.” Many companies label positions as remote but restrict hiring to specific regions (EMEA, APAC, or only within a certain country) due to legal, logistical, or tax constraints. Often, these limitations aren’t disclosed in the job listing, leaving candidates disappointed when they’re automatically disqualified based on location.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What to Do&lt;/em&gt;: Look carefully for any region-specific language in the job posting and, if possible, search the company’s hiring FAQs or career page for more details. Job boards like &lt;a href="https://weworkremotely.com/" rel="noopener noreferrer"&gt;We Work Remotely&lt;/a&gt; and &lt;a href="https://remoteok.com/" rel="noopener noreferrer"&gt;Remote OK&lt;/a&gt; often filter jobs by region, which can save you time by showing positions that align with your location.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Employee Lock-Up”
&lt;/h2&gt;

&lt;p&gt;Some companies post positions to relieve current employees under heavy workloads, even though they may not have immediate plans to hire. This tactic is often used to boost morale temporarily, by creating an impression that help is on the way.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What to Do&lt;/em&gt;: If you’ve applied to a role and don’t receive timely feedback or see the same listing repeated often, it might indicate that hiring isn’t a priority. Follow up on your application, and if you receive vague responses, consider exploring other options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reach Out to Recruiters Directly
&lt;/h2&gt;

&lt;p&gt;Don't just apply to hundreds of roles and leave it there. Sending a LinkedIn message to recruiters shows initiative, sets you apart from the crowd, and builds rapport. Making a memorable impression could make the recruiter more inclined to pick you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What to do&lt;/em&gt;: After applying, send a message to the recruiter on LinkedIn expressing your genuine interest in the role and highlighting something specific about the company that excites you. Personalized outreach shows initiative, making you more memorable than the average applicant.&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%2Fmgde87nrzcrpnozx3vxq.jpg" 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%2Fmgde87nrzcrpnozx3vxq.jpg" alt="job interview end happy image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are a list of good job boards to find remote worldwide jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://t.me/worldwideremote" rel="noopener noreferrer"&gt;Worldwide Remote&lt;/a&gt; (This is a telegram channel that vets and post only Worldwide remote jobs) 😍✅.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://remoteok.com/" rel="noopener noreferrer"&gt;RemoteOk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://remotive.com/remote-jobs" rel="noopener noreferrer"&gt;Remotive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://weworkremotely.com/" rel="noopener noreferrer"&gt;WeWorkRemotely&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trulyremote.co/" rel="noopener noreferrer"&gt;Truly remote&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodesk.co/remote-jobs" rel="noopener noreferrer"&gt;Nodesk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.careervault.io/remote" rel="noopener noreferrer"&gt;Careervault&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://workinstartups.com/jobs-search?location=remote&amp;amp;page=1" rel="noopener noreferrer"&gt;Workinstartups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.workingnomads.com/" rel="noopener noreferrer"&gt;Workingnomads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.trueup.io" rel="noopener noreferrer"&gt;TrueUp&lt;/a&gt; 😍&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Job hunting can feel like running a marathon—you’re giving it your all, but surprise hurdles pop up along the way. Don’t let them slow you down! Every setback is just part of the journey. Stay sharp, keep adjusting, and remember: every ‘no’ gets you closer to a ‘yes.’ &lt;br&gt;
Now, go turn those rejections into redirections! 🎉&lt;/p&gt;

</description>
      <category>developer</category>
      <category>community</category>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Custom Cursor in 4 Simple Steps – No External Libraries Needed!</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Tue, 21 Nov 2023 19:46:26 +0000</pubDate>
      <link>https://dev.to/chocoscoding/custom-cursor-in-4-simple-steps-no-external-libraries-needed-1ml2</link>
      <guid>https://dev.to/chocoscoding/custom-cursor-in-4-simple-steps-no-external-libraries-needed-1ml2</guid>
      <description>&lt;p&gt;Ever stumbled upon websites with mesmerizing cursors that take the user experience to the next level? You might think achieving that requires complex libraries or long styling, but it's actually easy.&lt;/p&gt;

&lt;p&gt;In just four simple steps and a few lines of code, you can bring that magic to your site. Let's dive in and make your cursor stand out! 💻✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Set Up useRef and Attach to the Div
&lt;/h2&gt;

&lt;p&gt;First things first, let's set up a useRef to grab our custom cursor div. This will serve as the canvas for our cursor movements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useRef&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;const&lt;/span&gt; &lt;span class="nx"&gt;CustomCursor&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;cursorRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cursorRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'custom-cursor'&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;CustomCursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Style It Up with Some CSS Magic
&lt;/h2&gt;

&lt;p&gt;Let's make our custom cursor visually appealing! Add this CSS code to give it a stylish look 🎇:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.custom-cursor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate3d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.custom-cursor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#000&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="c"&gt;/* Feel free to customize the size, colors, and border according to your taste! */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: The Magic of useEffect
&lt;/h2&gt;

&lt;p&gt;In this useEffect, we're creating a dynamic custom cursor for a React app. The mouseTransformer function adjusts the cursor's position based on mouse movement, providing a real-time, polished user experience. An event listener on the document triggers this function on mouse movement, creating a seamless dance between the cursor and user interaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&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;./style.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;// 🚀 Don't forget to import the CSS for your custom cursor!&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomCursor&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;cursorRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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="c1"&gt;// 🎨 Mouse transformation magic happens here!&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseTransformer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;clientX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&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;mouseX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clientX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cursorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientWidth&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cursorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientHeight&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;cursorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;cursorRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&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="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mouseTransformer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 🚀 Cleanup event listener on component unmount&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mouseTransformer&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cursorRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'custom-cursor'&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;CustomCursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Import and Let the Magic Begin
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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="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="nx"&gt;ReactDOM&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-dom&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;CustomCursor&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;./path/to/CustomCursor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&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;/* Other components */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CustomCursor&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="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like that! In just 4 steps, you've crafted your very own React custom cursor without relying on external libraries. 🌈✨ Get creative, experiment with styles, and make your website stand out with a cursor that's as unique.! &lt;/p&gt;

&lt;p&gt;Happy coding! 🚀🎨&lt;/p&gt;

</description>
      <category>react</category>
      <category>gsap</category>
      <category>javascript</category>
      <category>animation</category>
    </item>
    <item>
      <title>Js Devs: Position of you ++ or — matters</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Tue, 21 Nov 2023 15:51:01 +0000</pubDate>
      <link>https://dev.to/chocoscoding/js-devs-position-of-you-or-matters-4a49</link>
      <guid>https://dev.to/chocoscoding/js-devs-position-of-you-or-matters-4a49</guid>
      <description>&lt;p&gt;JavaScript provides powerful operators for manipulating numeric values ++ for incrementing and -- for decrementing. Understanding the nuances between postfix and prefix usage is crucial for precise programming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Postfix Increment and Decrement
&lt;/h3&gt;

&lt;p&gt;Postfix increment and decrement operators (i++ and i--) are used to change the value of a variable after its current value is used in an expression.&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;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;5&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;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: 5 (uses current value, then increments)&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;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Outputs: 6 (value has been incremented)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prefix Increment and Decrement
&lt;/h3&gt;

&lt;p&gt;Prefix increment and decrement operators (++i and --i) are used to change the value of a variable before its current value is used in an expression.&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;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;5&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="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: 6 (increments first, then uses the updated value)&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;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Outputs: 6 (value has been incremented)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  An extra example
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
With postfix
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Postfix decrement: prev--&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;inventoryCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&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;processSalePostfix&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;inventoryCount&lt;/span&gt; &lt;span class="o"&gt;&amp;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;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;Item sold! Remaining inventory:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inventoryCount&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;else&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;Item out of stock!&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="c1"&gt;// Simulate sales&lt;/span&gt;
&lt;span class="nf"&gt;processSalePostfix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Item sold! Remaining inventory: 5&lt;/span&gt;
&lt;span class="nf"&gt;processSalePostfix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Item sold! Remaining inventory: 4&lt;/span&gt;
&lt;span class="nf"&gt;processSalePostfix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Item sold! Remaining inventory: 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, with postfix decrement, the current inventory count is logged, and then the inventory count is decremented. This might be useful if you want to display the current inventory count before processing the sale.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;with prefix
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prefix decrement: --prev&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;inventoryCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&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;processSalePrefix&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="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;inventoryCount&lt;/span&gt; &lt;span class="o"&gt;&amp;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;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;Item sold! Remaining inventory:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inventoryCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;Item out of stock!&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="c1"&gt;// Simulate sales&lt;/span&gt;
&lt;span class="nf"&gt;processSalePrefix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Item sold! Remaining inventory: 4&lt;/span&gt;
&lt;span class="nf"&gt;processSalePrefix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Item sold! Remaining inventory: 3&lt;/span&gt;
&lt;span class="nf"&gt;processSalePrefix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Item sold! Remaining inventory: 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, with prefix decrement, the inventory count is decremented before checking if it's greater than 0. This might be useful if you want to ensure that the inventory count is updated before any other operations, such as logging or further processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In summary, postfix increment/decrement is useful when you need the current value before the change, and prefix increment/decrement is ideal when you need the updated value after the change. This nuanced understanding will undoubtedly enhance your proficiency as a JavaScript developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE FOR REACT DEVELOPERS:&lt;/strong&gt; Be careful with postfix if your values may be used before a rerender.&lt;/p&gt;

&lt;p&gt;Thanks for your time 🙂👍.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Pixel-Perfect Development with React Plugin from FIGMA</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Thu, 14 Sep 2023 13:53:22 +0000</pubDate>
      <link>https://dev.to/chocoscoding/pixel-perfect-development-with-react-plugin-from-figma-2eg</link>
      <guid>https://dev.to/chocoscoding/pixel-perfect-development-with-react-plugin-from-figma-2eg</guid>
      <description>&lt;p&gt;If you're a React web developer, you're likely familiar with the challenge of aligning your designs with your code. You may have experienced that frustrating feeling of your design not quite matching up to your expectations. I used to struggle with alignment issues and had to create multiple border lines to ensure everything lined up properly, but it didn't always produce the desired results.&lt;/p&gt;

&lt;p&gt;That's where Layout-greed comes in. This plugin, inspired by Figma's layout grid, guarantees precise alignment and consistency for every pixel in your project or product. So, if i design using a particular design grid scheme, you can copy it to your frontend project and build with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here are the 3 types of layout guidelines you get:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Columns
&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%2Fldv7skr6cu8rk40u4fjh.jpeg" alt="Columns" width="800" height="443"&gt;
&lt;/li&gt;
&lt;li&gt;Rows
&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%2Fsr4wfzsmdmgjo465w5nr.jpeg" alt="Rows" width="800" height="443"&gt;
&lt;/li&gt;
&lt;li&gt;Grid
&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%2Fgmhgdfee8b85jfyps7h4.jpeg" alt="Grid" width="800" height="443"&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://res.cloudinary.com/chocoscoding/video/upload/v1694686302/Untitled_1_wvxzdx.mp4" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;res.cloudinary.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
Looking good? See the demo below 👇
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/48g5tr"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use
&lt;/h2&gt;

&lt;p&gt;For yarn users - &lt;code&gt;yarn install layout-greed&lt;/code&gt;&lt;br&gt;
For npm users - &lt;code&gt;npm install layout-greed&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;Layout&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;layout-greed&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;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="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;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&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="nc"&gt;Layout&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;div&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;Check out &lt;a href="https://www.npmjs.com/package/layout-greed" rel="noopener noreferrer"&gt;layout greed on npm&lt;/a&gt; for more info.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I believe this would help a lot of developers who love to make accurate interpretations from designs while keeping it nice and crispy 🥰.&lt;br&gt;
So, tell me what you think. Is this something you would use? If not, tell me why 😉&lt;/p&gt;

</description>
      <category>figma</category>
      <category>frontend</category>
      <category>design</category>
      <category>ui</category>
    </item>
    <item>
      <title>NEXT.Js Link routing on steroids</title>
      <dc:creator>Chocoscoding - Oyeti Timileyin</dc:creator>
      <pubDate>Tue, 12 Sep 2023 12:59:43 +0000</pubDate>
      <link>https://dev.to/chocoscoding/nextjs-link-routing-on-steroids-1i06</link>
      <guid>https://dev.to/chocoscoding/nextjs-link-routing-on-steroids-1i06</guid>
      <description>&lt;p&gt;When building things with Next.JS 13, I previously had two main problems when using Next.JS  component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I sometimes had to compromise on the server components' awesomeness when dealing with more complex routing scenarios.&amp;nbsp;
e.g Using a route that requires a params
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&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;useParams&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;next/navigation&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;Link&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;next/link&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;Normal&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;//current page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Membership/Request&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;div&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Membership/Members */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/groups/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&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="s2"&gt;/manage/Membership/Members`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Membership&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Community/Members */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/groups/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&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="s2"&gt;/manage/Community/Members`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Community&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Content */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/groups/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&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="s2"&gt;/manage/Content`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/groups/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&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="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;div&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;ul&gt;
&lt;li&gt;Some unnecessarily overly long link strings in my href attributes. 😫
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&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;next/link&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;Normal&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="c1"&gt;//current page: http://localhost:3000/main/portfolio/flyingDay/info/colorScheme&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;div&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;/* go to page: http://localhost:3000/main/portfolio/flyingDay/info/colorScheme/secondary */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/main/portfolio/flyingDay/info/colorScheme/secondary`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;secondary&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/main/portfolio/flyingDay/info/typography */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/main/portfolio/flyingDay/info/typography`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;typography&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/main/portfolio/HappyMan */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/main/portfolio/HappyMan`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;HappyMan&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/main/portfolio/flyingDay */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/main/portfolio/flyingDay/info`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;main info&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;div&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;This becomes a lot more stressful and repetitive when building large web apps and you have to go through these... right???&lt;/p&gt;

&lt;p&gt;But guess what? Building large web applications doesn't have to be a constant source of stress and repetition! 😄 NEXT.js has introduced an amazing feature that will make you smile. 😊 Now, creating cleaner and more efficient links is a breeze, without giving up on server components.&lt;/p&gt;

&lt;p&gt;You can now create links as if routes are just like navigating through folders. Just like you would import from a files tree: &lt;/p&gt;

&lt;p&gt;So basically treat every / or route as a folder.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;abc&lt;/code&gt; --- i want to replace something in this path with abc&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./abc&lt;/code&gt; --- i want to replace something in this path with abc&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../abc&lt;/code&gt; --- i want to replace something in the parent path above the last path with abc&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../../abc&lt;/code&gt; --- i want to replace something 2 paths above the last path with abc&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../../../abc&lt;/code&gt; --- i want to replace something 3 pathsabove the last path with abc&lt;/p&gt;

&lt;p&gt;Here's how it looks in action:&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;import&lt;/span&gt; &lt;span class="nx"&gt;Link&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;next/link&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;Normal&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="c1"&gt;//current page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Membership/Request&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;div&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Membership/Members */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Members`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Membership&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`./Members`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Membership&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Community/Members */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`../Community/Members`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Community&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h/manage/Content */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`../Content`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/groups/2vz8t6svg7y63e56788h7h */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`../../`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;div&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&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;next/link&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;Normal&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="c1"&gt;//current page: http://localhost:3000/main/portfolio/flyingDay/info/colorScheme&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;div&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;/* go to page: http://localhost:3000/main/portfolio/flyingDay/info/colorScheme/secondary */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`colorScheme/secondary`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;secondary&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/main/portfolio/flyingDay/info/typography */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`typography`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;typography&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/main/portfolio/HappyMan */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`../../HappyMan`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;HappyMan&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;/* go to page: http://localhost:3000/main/portfolio/flyingDay */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`../`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;main info&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&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;div&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;&lt;strong&gt;With this method (path based href), We can:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid always using useParams hook.&lt;/li&gt;
&lt;li&gt;Be flexible in changing hrefs.&lt;/li&gt;
&lt;li&gt;Avoid too long href links in our code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can view the idea discussion on this feature &lt;a href="https://github.com/vercel/next.js/discussions/53533" rel="noopener noreferrer"&gt;here&lt;/a&gt;, &lt;/p&gt;

&lt;p&gt;On a scale of 1 - 10, what do you rate this feature ?&lt;br&gt;
If you have any questions, contributions or critique on this, I would love to hear them 🤗&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
      <category>link</category>
    </item>
  </channel>
</rss>
