<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged tutorials</title>
<link>https://coderlegion.com/tag/tutorials</link>
<description>Powered by Question2Answer</description>
<item>
<title>SEO Basics Every Frontend Developer Should Know</title>
<link>https://coderlegion.com/23011/seo-basics-every-frontend-developer-should-know</link>
<description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;SEO gets treated like it's purely a marketing job — write good content, use the right keywords, done. But a huge chunk of what actually affects search rankings is technical, and it lives entirely in the code, meaning it's the frontend developer's job whether anyone officially assigns it or not.&lt;/p&gt;
&lt;p&gt;Here's what I actually implement on every project, client or personal, without needing a marketing background.&lt;/p&gt;
&lt;h2 id=&quot;1-semantic-html-this-matters-more-than-you-think-&quot;&gt;1. Semantic HTML (This Matters More Than You Think)&lt;/h2&gt;
&lt;p&gt;Search engines read your HTML structure to understand what's important on the page.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Weak --&amp;gt;
&amp;lt;div class=&quot;title&quot;&amp;gt;Best Frontend Tools&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;text&quot;&amp;gt;Content here...&amp;lt;/div&amp;gt;

&amp;lt;!-- Semantic --&amp;gt;
&amp;lt;h1&amp;gt;Best Frontend Tools&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;Content here...&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;rules-to-follow-&quot;&gt;Rules to follow:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;One &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; per page, describing the main topic&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;&amp;lt;h2&amp;gt;, &amp;lt;h3&amp;gt;&lt;/code&gt; in proper hierarchical order, not just for visualsize&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;&amp;lt;nav&amp;gt;, &amp;lt;header&amp;gt;, &amp;lt;main&amp;gt;, &amp;lt;footer&amp;gt;, &amp;lt;article&amp;gt;&lt;/code&gt; where appropriate instead of generic &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s everywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-meta-tags-the-basics-actually-matter-&quot;&gt;2. Meta Tags (The Basics Actually Matter)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;15 Free Frontend Tools Every Developer Should Know | Your Site&amp;lt;/title&amp;gt;
  &amp;lt;meta name=&quot;description&quot; content=&quot;Discover 15 free frontend tools for design, CSS, icons, and testing — perfect for beginners and pros.&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; should be unique per page, under ~60 characters, with your main keyword near the front&lt;/li&gt;
&lt;li&gt;&lt;code&gt;meta description&lt;/code&gt; doesn't directly boost ranking, but it's what shows in search results — a good one improves click-through rate, which does matter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;viewport&lt;/code&gt; meta tag is required for mobile-friendliness, which Google explicitly factors into ranking&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-image-alt-text&quot;&gt;3. Image Alt Text&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img src=&quot;react-hooks-diagram.png&quot; alt=&quot;Diagram showing useState and useEffect hook lifecycle in React&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alt text serves two purposes: accessibility (screen readers rely on it) and SEO (search engines can't &quot;see&quot; images, only read this text). Never leave it empty on meaningful images, and never stuff it with random keywords — describe what's actually in the image.&lt;/p&gt;
&lt;h2 id=&quot;4-page-speed-a-direct-ranking-factor-&quot;&gt;4. Page Speed (A Direct Ranking Factor)&lt;/h2&gt;
&lt;p&gt;Google explicitly uses Core Web Vitals — loading speed, interactivity, and visual stability — as ranking signals. This connects directly to earlier articles in this series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Optimize images with Squoosh or TinyPNG (Article 1)&lt;/li&gt;
&lt;li&gt;Use max-width: 100% and proper responsive images instead of oversized&lt;br&gt;
files (Article 6)&lt;/li&gt;
&lt;li&gt;Lazy-load images below the fold: &lt;code&gt;&amp;lt;img loading=&quot;lazy&quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Check your score with Lighthouse and fix what it flags (Article 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A fast site isn't just a nice-to-have anymore — it's a direct, measurable ranking factor.&lt;/p&gt;
&lt;h2 id=&quot;5-mobile-friendliness&quot;&gt;5. Mobile-Friendliness&lt;/h2&gt;
&lt;p&gt;Google uses mobile-first indexing, meaning it primarily looks at your site's mobile version when determining rankings, even for desktop search results. Everything covered in Article 6 (Responsive Design) directly affects SEO, not just user experience.&lt;/p&gt;
&lt;h2 id=&quot;6-clean-descriptive-urls&quot;&gt;6. Clean, Descriptive URLs&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Weak:  yoursite.com/page?id=4829
Better: yoursite.com/blog/free-frontend-tools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Descriptive URLs help both search engines and users understand what a page is about before even clicking.&lt;/p&gt;
&lt;h2 id=&quot;7-internal-linking&quot;&gt;7. Internal Linking&lt;/h2&gt;
&lt;p&gt;Link related pages/articles to each other within your site (like this series does, referencing earlier articles). This helps search engines understand your site structure and helps visitors discover more of your content — both of which support better rankings over time.&lt;/p&gt;
&lt;h2 id=&quot;8-structured-data-optional-but-powerful-&quot;&gt;8. Structured Data (Optional but Powerful)&lt;/h2&gt;
&lt;p&gt;Adding Schema.org markup (JSON-LD format) helps search engines understand your content type — a blog post, a product, a review — and can unlock rich search result features like star ratings or FAQ dropdowns.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script type=&quot;application/ld+json&quot;&amp;gt;
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;Article&quot;,
  &quot;headline&quot;: &quot;SEO Basics Every Frontend Developer Should Know&quot;,
  &quot;author&quot;: &quot;Muhammad Farhan&quot;
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is more advanced and not essential for every project, but worth knowing it exists.&lt;/p&gt;
&lt;h2 id=&quot;common-beginner-mistakes&quot;&gt;Common Beginner Mistakes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for everything instead of semantic tags. Costs you nothing to fix and genuinely helps both SEO and accessibility.&lt;/li&gt;
&lt;li&gt;Skipping alt text entirely. Easy to forget, meaningfully impactful when done right.&lt;/li&gt;
&lt;li&gt;Shipping unoptimized images. The single most common performance (and therefore SEO) killer on beginner and even client projects.&lt;/li&gt;
&lt;li&gt;Ignoring mobile experience because the desktop version &quot;looks fine.&quot; Google mostly doesn't care how your desktop version looks.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;You don't need to become an SEO specialist to meaningfully improve how a site ranks — most of the technical fundamentals are just good development practices you should be doing anyway: semantic HTML, fast load times, proper alt text, and mobile responsiveness. Build these habits into every project from the start, and SEO stops being a separate task tacked on at the end.&lt;/p&gt;
&lt;p&gt;That wraps this 15-article series — if you've followed along from Article 1, you now have a solid, practical foundation across CSS, React, tooling, deployment, freelancing, and SEO. Go build something with it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23011/seo-basics-every-frontend-developer-should-know</guid>
<pubDate>Tue, 01 Sep 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>How I Landed My First Freelance Client as a Frontend Developer</title>
<link>https://coderlegion.com/23010/how-i-landed-my-first-freelance-client-as-a-frontend-developer</link>
<description>&lt;h2 id=&quot;introduction-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I'm not going to pretend this was some overnight success story — it wasn't. It took real, unglamorous effort before anything happened. But I think that's exactly why this story is more useful than the polished &quot;I made $10k my first month&quot; posts you see floating around.&lt;/p&gt;
&lt;p&gt;Here's honestly what happened, and what I'd tell any beginner developer trying to land their first client right now.&lt;/p&gt;
&lt;h2 id=&quot;where-i-started&quot;&gt;Where I Started&lt;/h2&gt;
&lt;p&gt;I had a portfolio (see Article 12 for what actually goes into a good one), a few personal projects, and zero client work. No reviews, no testimonials, nothing to point to except &quot;trust me, I can build this.&quot;&lt;/p&gt;
&lt;p&gt;That's a genuinely hard position to sell from — and I want to be upfront about that instead of skipping past it.&lt;/p&gt;
&lt;h2 id=&quot;what-didn-t-work&quot;&gt;What Didn't Work&lt;/h2&gt;
&lt;p&gt;Mass-applying to generic Fiverr/Upwork gigs with a copy-pasted message. I sent probably 15-20 near-identical proposals early on. Zero responses. Clients can tell instantly when a message wasn't written specifically for their project.&lt;/p&gt;
&lt;p&gt;Underpricing to &quot;compete.&quot; I dropped my rate low, assuming price was the deciding factor. It wasn't — the clients I was losing to weren't choosing based on price; they were choosing based on trust, and a rock-bottom price can actually read as a red flag rather than a selling point.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-worked&quot;&gt;What Actually Worked&lt;/h2&gt;
&lt;h3 id=&quot;1-i-stopped-applying-blind-and-started-researching-the-client-first&quot;&gt;1. I Stopped Applying Blind and Started Researching the Client First&lt;/h3&gt;
&lt;p&gt;Before sending a proposal, I'd actually look at the client's existing website or business, and mention something specific in my message.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Instead of: &quot;Hi, I'm a frontend developer available for your project.&quot;

I wrote: &quot;I checked out your current site — the mobile menu doesn't
open properly on iPhone Safari, which is likely costing you visitors.
I can fix that as part of rebuilding your homepage.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That single specific observation did more than 20 generic messages combined.&lt;/p&gt;
&lt;h3 id=&quot;2-i-led-with-a-live-demo-not-just-a-portfolio-link&quot;&gt;2. I Led With a Live Demo, Not Just a Portfolio Link&lt;/h3&gt;
&lt;p&gt;For one prospect, instead of just sending my portfolio, I built a quick, rough homepage mockup based on their existing brand and sent a live preview link alongside my proposal. It took maybe 90 minutes, and it was the deciding factor in getting that first &quot;yes.&quot;&lt;/p&gt;
&lt;p&gt;This doesn't scale to every application — but for a client you genuinely want, showing instead of just telling is worth the extra effort.&lt;/p&gt;
&lt;h3 id=&quot;3-i-asked-for-a-testimonial-immediately-after-finishing&quot;&gt;3. I Asked for a Testimonial Immediately After Finishing&lt;/h3&gt;
&lt;p&gt;The moment that first project wrapped up and the client was happy, I asked directly for a short written testimonial and permission to list the project in my portfolio. That single testimonial made every proposal after it noticeably stronger — I finally had proof, not just a promise.&lt;/p&gt;
&lt;h3 id=&quot;4-i-treated-the-first-project-as-a-portfolio-investment-not-just-a-paycheck&quot;&gt;4. I Treated the First Project as a Portfolio Investment, Not Just a Paycheck&lt;/h3&gt;
&lt;p&gt;I overdelivered slightly on that first project — a bit more polish, a bit more communication than strictly required. It wasn't about being a pushover; it was a deliberate decision, because that project was going to be my proof for every client after it.&lt;/p&gt;
&lt;h2 id=&quot;what-i-d-tell-beginners-specifically&quot;&gt;What I'd Tell Beginners Specifically&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Your first client won't come from volume — it'll come from one genuinely well-researched, specific pitch. Send fewer, better proposals.&lt;/li&gt;
&lt;li&gt;A rough live demo beats a polished portfolio link for a serious prospect. It proves you can actually do the specific thing they need, not just that you can build things in general.&lt;/li&gt;
&lt;li&gt;Don't undercharge to compete. Price confidently for the value, and let your specificity and communication build trust instead.&lt;/li&gt;
&lt;li&gt;Ask for a testimonial the moment you finish, while the client is happiest. Don't wait — that window closes fast.&lt;/li&gt;
&lt;li&gt;Your first project is marketing, not just income. Treat it that way, and the second client comes noticeably easier than the first.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;final-thoughts-1&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;There's no trick that skips the hard part — you do have to put in real, specific effort before that first client says yes. But once you have that first project and testimonial, everything after it gets meaningfully easier, because you're no longer selling a promise. You're selling proof.&lt;/p&gt;
&lt;p&gt;If you're still working on landing your first client, I'd genuinely love to hear where you're stuck — drop it in the comments.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23010/how-i-landed-my-first-freelance-client-as-a-frontend-developer</guid>
<pubDate>Fri, 28 Aug 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>Common CSS Mistakes Beginners Make (and How to Fix Them)</title>
<link>https://coderlegion.com/23008/common-css-mistakes-beginners-make-and-how-to-fix-them</link>
<description>&lt;h2 id=&quot;introduction-2&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Every one of these mistakes cost me real debugging time when I was learning. Not because CSS is inherently confusing — but because nobody explained why these things happen, just that they do. Understanding the &quot;why&quot; is what actually prevents you from repeating them.&lt;/p&gt;
&lt;h2 id=&quot;1-the-box-model-confusion&quot;&gt;1. The Box Model Confusion&lt;/h2&gt;
&lt;p&gt;By default, &lt;strong&gt;width&lt;/strong&gt; and &lt;strong&gt;height&lt;/strong&gt; don't include padding and border — meaning a box you set to &lt;strong&gt;300px&lt;/strong&gt; wide can visually render wider once padding is added.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box {
  width: 300px;
  padding: 20px;
  border: 2px solid black;
  /* Actual rendered width: 300 + 20+20 + 2+2 = 344px */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt;: set this once, globally, at the start of every project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* {
  box-sizing: border-box;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now &lt;strong&gt;width: 300px&lt;/strong&gt; means the element is always 300px total, padding and border included. This single line prevents a huge number of layout bugs.&lt;/p&gt;
&lt;h2 id=&quot;2-margin-collapse&quot;&gt;2. Margin Collapse&lt;/h2&gt;
&lt;p&gt;Two vertical margins between sibling elements don't add together — they collapse into the larger of the two.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.first { margin-bottom: 20px; }
.second { margin-top: 30px; }
/* Actual gap between them: 30px, NOT 50px */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confuses beginners constantly because it seems inconsistent — but it's expected browser behavior for vertical margins specifically (doesn't apply to horizontal margins, or to Flexbox/Grid &lt;code&gt;gap&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The fix: use &lt;code&gt;gap&lt;/code&gt; on a flex or grid container instead of relying on margins between children — it doesn't collapse and is far more predictable.&lt;/p&gt;
&lt;h2 id=&quot;3-overusing-important&quot;&gt;3. Overusing &lt;code&gt;!important&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;.button {
  background: blue !important;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;!important&lt;/code&gt; overrides normal CSS specificity rules — which feels like a quick fix, but it creates a mess later. Once you have several &lt;code&gt;!important&lt;/code&gt; rules fighting each other, debugging becomes genuinely painful because normal specificity logic no longer applies.&lt;/p&gt;
&lt;p&gt;The fix: understand specificity instead. IDs beat classes, classes beat elements. If you're reaching for &lt;code&gt;!important&lt;/code&gt;, it usually means a more specific selector (or restructuring your CSS) would solve it more cleanly.&lt;/p&gt;
&lt;h2 id=&quot;4-not-understanding-position-absolute&quot;&gt;4. Not Understanding &lt;code&gt;position: absolute&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;.tooltip {
  position: absolute;
  top: 0;
  left: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Beginners often expect this to position relative to the whole page. In reality, &lt;code&gt;position: absolute&lt;/code&gt; positions relative to the nearest ancestor with &lt;code&gt;position: relative&lt;/code&gt; (or &lt;code&gt;absolute/fixed&lt;/code&gt;) set. If no ancestor has that, it &lt;code&gt;positions relative&lt;/code&gt; to the whole document — which is rarely what you actually want.&lt;/p&gt;
&lt;p&gt;The fix: always set &lt;code&gt;position: relative&lt;/code&gt; on the parent container first:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  position: relative;
}
.badge {
  position: absolute;
  top: 8px;
  right: 8px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;5-fighting-flexbox-grid-instead-of-reading-the-docs&quot;&gt;5. Fighting Flexbox/Grid Instead of Reading the Docs&lt;/h2&gt;
&lt;p&gt;A very common beginner pattern: not getting the exact spacing/alignment you want, then adding random margins and padding until it &quot;looks right&quot; by trial and error.&lt;/p&gt;
&lt;p&gt;The fix: learn &lt;code&gt;justify-content, align-items,&lt;/code&gt; and &lt;code&gt;gap&lt;/code&gt; properly (covered fully in Article 2). Once you understand these three properties, most alignment problems have a direct, one-line solution instead of a pile of guessed margins.&lt;/p&gt;
&lt;h2 id=&quot;6-not-resetting-default-browser-styles&quot;&gt;6. Not Resetting Default Browser Styles&lt;/h2&gt;
&lt;p&gt;Browsers apply their own default styles to elements (&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; gets bullet points and padding, &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; gets specific margins, etc.), and these defaults are inconsistent across browsers.&lt;/p&gt;
&lt;p&gt;The fix: use a simple CSS reset at the top of your stylesheet, or use Tailwind CSS, which includes a solid reset (Preflight) automatically.&lt;/p&gt;
&lt;h2 id=&quot;7-specificity-wars-from-nested-selectors&quot;&gt;7. Specificity Wars from Nested Selectors&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;.card .header .title span {
  color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deeply nested selectors like this become extremely hard to override later, since they carry heavy specificity.&lt;/p&gt;
&lt;p&gt;The fix: keep selectors as flat as possible. A single well-named class (&lt;code&gt;.card-title&lt;/code&gt;) is easier to maintain than four levels of nesting.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts-2&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Almost every CSS mistake on this list comes down to one thing: not understanding why the browser is doing what it's doing, and reaching for a quick patch instead. Once you understand the box model, specificity, and positioning contexts properly, CSS debugging goes from guesswork to genuinely logical problem-solving.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23008/common-css-mistakes-beginners-make-and-how-to-fix-them</guid>
<pubDate>Tue, 25 Aug 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>JavaScript ES6+ Features Every Frontend Developer Should Master</title>
<link>https://coderlegion.com/23003/javascript-es6-features-every-frontend-developer-should-master</link>
<description>&lt;h2 id=&quot;introduction-3&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If you learned JavaScript from an older tutorial, there's a decent chance you're writing more code than necessary without realizing it. Modern JavaScript (officially called ES6 and beyond, first released in 2015) added features that make everyday code shorter, more readable, and honestly just more enjoyable to write.&lt;/p&gt;
&lt;p&gt;If you're using React, you're already using several of these features without knowing their names. Let's fix that.&lt;/p&gt;
&lt;h2 id=&quot;1-arrow-functions&quot;&gt;1. Arrow Functions&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// Old way
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) =&amp;gt; a + b;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For single-expression functions, you can skip the curly braces and &lt;strong&gt;return&lt;/strong&gt; keyword entirely — the expression's result is returned automatically.&lt;/p&gt;
&lt;p&gt;Where you'll actually use this: callbacks, all the time.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const doubled = numbers.map(num =&amp;gt; num * 2);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;2-destructuring&quot;&gt;2. Destructuring&lt;/h2&gt;
&lt;p&gt;Pulling values out of objects or arrays into individual variables.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const user = { name: &quot;Farhan&quot;, role: &quot;Developer&quot; };

// Old way
const name = user.name;
const role = user.role;

// Destructuring
const { name, role } = user;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Works with arrays too:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const [first, second] = [&quot;React&quot;, &quot;Tailwind&quot;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is exactly what's happening every time you write const [count, setCount] = useState(0) in React.&lt;/p&gt;
&lt;h2 id=&quot;3-spread-and-rest-operators-&quot;&gt;3. Spread and Rest Operators (...)&lt;/h2&gt;
&lt;p&gt;The same three dots, doing two different jobs depending on context.&lt;/p&gt;
&lt;p&gt;Spread — expands an array or object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const original = [1, 2, 3];
const copy = [...original, 4]; // [1, 2, 3, 4]

const user = { name: &quot;Farhan&quot; };
const updatedUser = { ...user, role: &quot;Developer&quot; };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rest — collects multiple values into one array/object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function sum(...numbers) {
  return numbers.reduce((total, n) =&amp;gt; total + n, 0);
}
sum(1, 2, 3, 4); // 10
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;4-template-literals&quot;&gt;4. Template Literals&lt;/h2&gt;
&lt;p&gt;String building using backticks instead of concatenation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const name = &quot;Farhan&quot;;

// Old way
const greeting = &quot;Hello, &quot; + name + &quot;! You have &quot; + count + &quot; messages.&quot;;

// Template literal
const greeting = `Hello, ${name}! You have ${count} messages.`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also supports multi-line strings naturally, without \n characters.&lt;/p&gt;
&lt;h2 id=&quot;5-optional-chaining-&quot;&gt;5. Optional Chaining (?.)&lt;/h2&gt;
&lt;p&gt;Safely access deeply nested properties without your code crashing if something is missing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Old way — risky if 'address' doesn't exist
const city = user.address.city;

// Optional chaining — returns undefined instead of crashing
const city = user?.address?.city;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extremely useful when working with API data, where fields aren't always guaranteed to exist.&lt;/p&gt;
&lt;h2 id=&quot;6-nullish-coalescing-&quot;&gt;6. Nullish Coalescing (??)&lt;/h2&gt;
&lt;p&gt;Provides a fallback value, but only when the original value is &lt;strong&gt;null&lt;/strong&gt; or &lt;strong&gt;undefined&lt;/strong&gt; (unlike &lt;strong&gt;||&lt;/strong&gt;, which also triggers on &lt;strong&gt;0, &quot;&quot;,&lt;/strong&gt; or &lt;strong&gt;false&lt;/strong&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const count = userCount ?? 0;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;strong&gt;userCount&lt;/strong&gt; is &lt;strong&gt;0&lt;/strong&gt;, &lt;strong&gt;||&lt;/strong&gt; would incorrectly fall back to the default. &lt;strong&gt;??&lt;/strong&gt; correctly keeps it as &lt;strong&gt;0&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;7-array-methods-map-filter-reduce&quot;&gt;7. Array Methods: map, filter, reduce&lt;/h2&gt;
&lt;p&gt;The trio that replaces almost every manual &lt;strong&gt;for&lt;/strong&gt; loop you'd otherwise write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const users = [
  { name: &quot;Ali&quot;, active: true },
  { name: &quot;Sara&quot;, active: false },
];

const activeNames = users
  .filter(user =&amp;gt; user.active)
  .map(user =&amp;gt; user.name);
// [&quot;Ali&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;filter&lt;/strong&gt; keeps items matching a condition. &lt;strong&gt;map&lt;/strong&gt; transforms each item. &lt;strong&gt;reduce&lt;/strong&gt; combines everything into a single value (a sum, an object, whatever you need).&lt;/p&gt;
&lt;h2 id=&quot;common-beginner-mistakes-1&quot;&gt;Common Beginner Mistakes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Mixing arrow functions and &lt;strong&gt;this&lt;/strong&gt; incorrectly. Arrow functions don't have their own &lt;strong&gt;this&lt;/strong&gt; — they inherit it from the surrounding scope. This trips people up in class components or event handlers occasionally.&lt;/li&gt;
&lt;li&gt;Overusing optional chaining to hide real bugs. &lt;strong&gt;?.&lt;/strong&gt; is for genuinely optional data, not a substitute for fixing broken logic upstream.&lt;/li&gt;
&lt;li&gt;Forgetting &lt;strong&gt;map&lt;/strong&gt; returns a new array. It doesn't modify the original array — a common source of &quot;why isn't my state updating&quot; bugs in React.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;final-thoughts-3&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;These seven features cover probably 90% of what &quot;modern JavaScript&quot; actually means in day-to-day frontend work. If you're comfortable with all of them, reading React code (and most modern codebases) gets significantly easier, because this is the syntax nearly everyone writes in now.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23003/javascript-es6-features-every-frontend-developer-should-master</guid>
<pubDate>Tue, 18 Aug 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>CSS Animations for Beginners: Transitions, Keyframes &amp; Transforms</title>
<link>https://coderlegion.com/23001/css-animations-for-beginners-transitions-keyframes-transforms</link>
<description>&lt;h2 id=&quot;introduction-4&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;CSS animations were the thing that made me actually enjoy frontend development. Building a static layout is satisfying, but the moment something moves smoothly on hover or fades in on load, a project suddenly feels alive.&lt;/p&gt;
&lt;p&gt;The good news: you only need three concepts to cover almost every animation you'll want to build — transitions, transforms, and keyframes. Let's go through all three.&lt;/p&gt;
&lt;h2 id=&quot;1-transitions-smoothing-out-state-changes&quot;&gt;1. Transitions — Smoothing Out State Changes&lt;/h2&gt;
&lt;p&gt;A transition smooths out a property change between two states (like normal and hover).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.button {
  background-color: #3b82f6;
  transition: background-color 0.3s ease;
}

.button:hover {
  background-color: #2563eb;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without &lt;strong&gt;transition&lt;/strong&gt;, the color change would be instant. With it, the color smoothly shifts over 0.3 seconds.&lt;/p&gt;
&lt;p&gt;Syntax breakdown: &lt;strong&gt;transition: [property] [duration] [easing];&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Tailwind:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;button class=&quot;bg-blue-500 hover:bg-blue-600 transition duration-300&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;2-transform-moving-scaling-rotating&quot;&gt;2. Transform — Moving, Scaling, Rotating&lt;/h2&gt;
&lt;p&gt;transform changes an element's position, size, or rotation without affecting the layout of surrounding elements.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  transition: transform 0.3s ease;
}

.card:hover {
  transform: translateY(-8px) scale(1.02);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This lifts a card slightly and grows it a tiny bit on hover — a very common effect on portfolio sites and product cards.&lt;/p&gt;
&lt;h2 id=&quot;common-transform-values-&quot;&gt;Common transform values:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;translateY(-8px)&lt;/strong&gt; — moves up&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;scale(1.05)&lt;/strong&gt; — grows by 5%&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rotate(5deg)&lt;/strong&gt; — rotates slightly&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;translateX(20px)&lt;/strong&gt; — moves right&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;In Tailwind:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;transition hover:-translate-y-2 hover:scale-105&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3-keyframes-multi-step-animations&quot;&gt;3. Keyframes — Multi-Step Animations&lt;/h2&gt;
&lt;p&gt;Transitions handle two states. &lt;strong&gt;@keyframes&lt;/strong&gt; handles animations with multiple steps, or ones that run automatically without needing a trigger like &lt;strong&gt;:hover&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.hero-title {
  animation: fadeInUp 0.8s ease-out;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes an element fade in while sliding up slightly — a very common &quot;page load&quot; effect.&lt;/p&gt;
&lt;p&gt;You can also define multiple steps with percentages:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.notification-dot {
  animation: pulse 2s infinite;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a continuous pulsing effect, useful for notification badges or &quot;live&quot; indicators.&lt;/p&gt;
&lt;h2 id=&quot;putting-it-together-a-real-example&quot;&gt;Putting It Together: A Real Example&lt;/h2&gt;
&lt;p&gt;Here's a button with a hover lift, a smooth color transition, and a subtle entrance animation on page load:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.cta-button {
  background-color: #3b82f6;
  transition: all 0.3s ease;
  animation: fadeIn 0.6s ease-in;
}

.cta-button:hover {
  background-color: #2563eb;
  transform: translateY(-4px);
  box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is genuinely how most polished-feeling buttons on real websites are built — nothing exotic, just transitions and transforms combined thoughtfully.&lt;/p&gt;
&lt;h2 id=&quot;common-beginner-mistakes-2&quot;&gt;Common Beginner Mistakes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Animating too many properties at once. Subtlety wins — one or two properties changing smoothly looks more professional than five things moving at once.&lt;/li&gt;
&lt;li&gt;Using &lt;strong&gt;all&lt;/strong&gt; in transitions carelessly. &lt;strong&gt;transition: all 0.3s&lt;/strong&gt; works, but is slightly less performant than specifying exact properties like &lt;strong&gt;transition: transform 0.3s, background-color 0.3s&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Animating &lt;strong&gt;width/height/top/left&lt;/strong&gt; instead of &lt;strong&gt;transform&lt;/strong&gt;. These properties trigger layout recalculation and can feel janky. &lt;strong&gt;transform&lt;/strong&gt; and &lt;strong&gt;opacity&lt;/strong&gt; are GPU-accelerated and much smoother.&lt;/li&gt;
&lt;li&gt;Overusing &lt;strong&gt;infinite&lt;/strong&gt; animations. A pulsing badge is fine. A constantly bouncing hero heading gets annoying fast — use continuous animation sparingly.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;final-thoughts-4&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;You don't need a JavaScript animation library for most of what makes a website feel polished — smooth hovers, subtle lifts, and clean entrance animations are all achievable with plain CSS. Start by adding a transition to every hover state in your next project and see how much more &quot;finished&quot; it instantly feels.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23001/css-animations-for-beginners-transitions-keyframes-transforms</guid>
<pubDate>Tue, 11 Aug 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>How to Build Your First React Component (Step-by-Step)</title>
<link>https://coderlegion.com/23000/how-to-build-your-first-react-component-step-by-step</link>
<description>&lt;h2 id=&quot;introduction-5&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Your first React component doesn't need to be complicated. In fact, the biggest mistake beginners make is trying to build something too ambitious right away and getting stuck on concepts they haven't learned yet.&lt;/p&gt;
&lt;p&gt;We're building something practical and genuinely useful: a reusable Testimonial Card component — the kind of thing that shows up in real portfolios and client projects constantly.&lt;/p&gt;
&lt;h2 id=&quot;step-1-understand-what-a-component-actually-is&quot;&gt;Step 1: Understand What a Component Actually Is&lt;/h2&gt;
&lt;p&gt;A React component is just a JavaScript function that returns some JSX (HTML-like syntax). That's the whole concept.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Greeting() {
  return &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You use it like an HTML tag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Greeting /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-2-build-the-static-version-first&quot;&gt;Step 2: Build the Static Version First&lt;/h2&gt;
&lt;p&gt;Before adding any dynamic data, get the layout right with hardcoded content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function TestimonialCard() {
  return (
    &amp;lt;div className=&quot;bg-slate-800 rounded-2xl p-6 max-w-sm shadow-lg&quot;&amp;gt;
      &amp;lt;p className=&quot;text-slate-300 mb-4&quot;&amp;gt;
        &quot;This developer delivered exactly what we needed, on time and with great communication.&quot;
      &amp;lt;/p&amp;gt;
      &amp;lt;div className=&quot;flex items-center gap-3&quot;&amp;gt;
        &amp;lt;div className=&quot;w-10 h-10 rounded-full bg-blue-500&quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;p className=&quot;text-white font-semibold&quot;&amp;gt;Sarah Ahmed&amp;lt;/p&amp;gt;
          &amp;lt;p className=&quot;text-slate-400 text-sm&quot;&amp;gt;Product Manager&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice: no state, no props, nothing dynamic. Just structure and styling. This is genuinely how you should approach every new component — get the static layout right first.&lt;/p&gt;
&lt;h2 id=&quot;step-3-make-it-reusable-with-props&quot;&gt;Step 3: Make It Reusable with Props&lt;/h2&gt;
&lt;p&gt;Right now this card only shows one testimonial. Props let you reuse the same component with different data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function TestimonialCard({ quote, name, role }) {
  return (
    &amp;lt;div className=&quot;bg-slate-800 rounded-2xl p-6 max-w-sm shadow-lg&quot;&amp;gt;
      &amp;lt;p className=&quot;text-slate-300 mb-4&quot;&amp;gt;&quot;{quote}&quot;&amp;lt;/p&amp;gt;
      &amp;lt;div className=&quot;flex items-center gap-3&quot;&amp;gt;
        &amp;lt;div className=&quot;w-10 h-10 rounded-full bg-blue-500&quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;p className=&quot;text-white font-semibold&quot;&amp;gt;{name}&amp;lt;/p&amp;gt;
          &amp;lt;p className=&quot;text-slate-400 text-sm&quot;&amp;gt;{role}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you use it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;TestimonialCard
  quote=&quot;This developer delivered exactly what we needed, on time.&quot;
  name=&quot;Sarah Ahmed&quot;
  role=&quot;Product Manager&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;{ quote, name, role }&lt;/strong&gt; is destructuring the props object — same as writing &lt;strong&gt;props.quote, props.name, props.role&lt;/strong&gt;, just cleaner.&lt;/p&gt;
&lt;h2 id=&quot;step-4-render-a-list-of-them&quot;&gt;Step 4: Render a List of Them&lt;/h2&gt;
&lt;p&gt;In a real project, you'd map over an array of testimonial data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const testimonials = [
  { quote: &quot;Great work, fast turnaround.&quot;, name: &quot;Ali Raza&quot;, role: &quot;Founder&quot; },
  { quote: &quot;Clean code and clear communication.&quot;, name: &quot;Sarah Ahmed&quot;, role: &quot;PM&quot; },
  { quote: &quot;Would hire again without hesitation.&quot;, name: &quot;James Lee&quot;, role: &quot;CTO&quot; },
];

function TestimonialGrid() {
  return (
    &amp;lt;div className=&quot;grid md:grid-cols-3 gap-6 p-6&quot;&amp;gt;
      {testimonials.map((item, index) =&amp;gt; (
        &amp;lt;TestimonialCard key={index} {...item} /&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;{...item}&lt;/strong&gt; spreads the object properties as individual props automatically — a common React pattern once you're comfortable with the basics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; the key &lt;strong&gt;prop&lt;/strong&gt; is required whenever you render a list. React uses it to track which items changed. In a real project, use a unique ID from your data rather than the array index if possible.&lt;/p&gt;
&lt;h2 id=&quot;step-5-add-a-bit-of-interactivity-optional-&quot;&gt;Step 5: Add a Bit of Interactivity (Optional)&lt;/h2&gt;
&lt;p&gt;Want to show a &quot;Read more&quot; toggle for long quotes? That's where &lt;strong&gt;useState&lt;/strong&gt; comes in — covered in detail in Article 5, but here's the quick version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function TestimonialCard({ quote, name, role }) {
  const [expanded, setExpanded] = useState(false);

  return (
    &amp;lt;div className=&quot;bg-slate-800 rounded-2xl p-6 max-w-sm shadow-lg&quot;&amp;gt;
      &amp;lt;p className={`text-slate-300 mb-4 ${!expanded &amp;amp;&amp;amp; &quot;line-clamp-2&quot;}`}&amp;gt;
        &quot;{quote}&quot;
      &amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setExpanded(!expanded)} className=&quot;text-blue-400 text-sm mb-4&quot;&amp;gt;
        {expanded ? &quot;Show less&quot; : &quot;Read more&quot;}
      &amp;lt;/button&amp;gt;
      {/* rest of the card */}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;common-beginner-mistakes-3&quot;&gt;Common Beginner Mistakes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Trying to add state and interactivity before the static layout is right. Get the structure and styling working first — add logic after.&lt;/li&gt;
&lt;li&gt;Forgetting the &lt;strong&gt;key&lt;/strong&gt; prop when rendering lists. React will warn you in the console — don't ignore that warning.&lt;/li&gt;
&lt;li&gt;Not destructuring props. Writing &lt;strong&gt;props.quote&lt;/strong&gt; everywhere instead of destructuring is more typing and harder to read.&lt;/li&gt;
&lt;li&gt;Building one giant component instead of small, focused ones. If a component is doing three different jobs, split it into three components.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;final-thoughts-5&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Building your first real component is less about React &quot;magic&quot; and more about breaking a UI down into small, reusable pieces — static first, then props, then interactivity if needed. Rebuild this same pattern (static → props → list → interactivity) for your next few components and it'll start feeling automatic.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Muhammad Farhan is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23000/how-to-build-your-first-react-component-step-by-step</guid>
<pubDate>Fri, 07 Aug 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>Responsive Design 101: How to Make Any Website Mobile-Friendly</title>
<link>https://coderlegion.com/22995/responsive-design-101-how-to-make-any-website-mobile-friendly</link>
<description>&lt;h2 id=&quot;introduction-6&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The first website I ever built looked great on my laptop and completely broken on my phone. Text overflowing, buttons cut off, images stretched way too big. That's the exact moment &quot;responsive design&quot; stopped being a buzzword and became something I actually had to understand.&lt;/p&gt;
&lt;p&gt;Here's the good news: responsive design isn't complicated once you learn a handful of core habits. This article covers exactly those.&lt;/p&gt;
&lt;h2 id=&quot;mobile-first-start-small-then-grow&quot;&gt;Mobile-First: Start Small, Then Grow&lt;/h2&gt;
&lt;p&gt;The most important mindset shift: design for the smallest screen first, then add complexity as the screen grows — not the other way around.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Base styles = mobile */
.container {
  display: flex;
  flex-direction: column;
}

/* Then adjust for larger screens */
@media (min-width: 768px) {
  .container {
    flex-direction: row;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Tailwind, this is built into the framework by default:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;flex flex-col md:flex-row&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No media query needed — flex-col is the mobile default, md:flex-row overrides it on tablets and up.&lt;/p&gt;
&lt;h3 id=&quot;understanding-breakpoints&quot;&gt;Understanding Breakpoints&lt;/h3&gt;
&lt;p&gt;A breakpoint is a screen width where your layout changes. Tailwind's defaults are a solid starting point for almost any project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;(none)&lt;/strong&gt; — Default styles apply to &lt;strong&gt;all screen sizes&lt;/strong&gt; starting from &lt;strong&gt;0px&lt;br&gt;
(Mobile)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sm:&lt;/strong&gt; — Applies styles on screens &lt;strong&gt;640px and wider&lt;/strong&gt; (Large phones).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;md:&lt;/strong&gt; — Applies styles on screens &lt;strong&gt;768px and wider&lt;/strong&gt; (Tablets).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;lg:&lt;/strong&gt; — Applies styles on screens &lt;strong&gt;1024px and wider&lt;/strong&gt; (Laptops).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;xl:&lt;/strong&gt; — Applies styles on screens &lt;strong&gt;1280px and wider&lt;/strong&gt; (Desktops).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You rarely need custom breakpoints — these five cover the vast majority of real devices.&lt;/p&gt;
&lt;h3 id=&quot;flexible-units-over-fixed-pixels&quot;&gt;Flexible Units Over Fixed Pixels&lt;/h3&gt;
&lt;p&gt;Fixed pixel widths break responsive layouts. Use flexible units instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;%&lt;/strong&gt; — relative to the parent container&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rem&lt;/strong&gt; — relative to the root font size (better than px for text)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vw / vh&lt;/strong&gt; — relative to viewport width/height&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fr&lt;/strong&gt; — flexible fraction, used in CSS Grid&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;/* Breaks on small screens */
.card { width: 400px; }

/* Adapts to any screen */
.card { width: 100%; max-width: 400px; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That second version is the pattern to remember: set a &lt;strong&gt;max-width&lt;/strong&gt; for large screens, but let it shrink to &lt;strong&gt;100%&lt;/strong&gt; on smaller ones.&lt;/p&gt;
&lt;h3 id=&quot;responsive-images&quot;&gt;Responsive Images&lt;/h3&gt;
&lt;p&gt;Images are the #1 cause of layout breakage for beginners. The fix is almost always this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;img {
  max-width: 100%;
  height: auto;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Tailwind:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img src=&quot;photo.jpg&quot; class=&quot;max-w-full h-auto&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures an image never overflows its container, regardless of screen size, while keeping its aspect ratio intact.&lt;/p&gt;
&lt;h3 id=&quot;testing-your-responsive-design&quot;&gt;Testing Your Responsive Design&lt;/h3&gt;
&lt;p&gt;Don't just resize your browser window manually — use these instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chrome DevTools Device Mode (Ctrl+Shift+M) — simulates real device sizes, including touch input&lt;/li&gt;
&lt;li&gt;Responsively App — tests multiple device sizes side by side, syncing scroll and clicks (covered in Article 1)&lt;/li&gt;
&lt;li&gt;Actually open the site on your own phone before calling it done — emulators are close, but not perfect&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;common-beginner-mistakes-4&quot;&gt;Common Beginner Mistakes&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Designing desktop-first, then trying to &quot;fix&quot; mobile later. Almost always results in more work and more bugs.&lt;/li&gt;
&lt;li&gt;Fixed-width containers. &lt;strong&gt;width: 1200px&lt;/strong&gt; will always cause horizontal scrolling on smaller screens. Use &lt;strong&gt;max-width&lt;/strong&gt; instead.&lt;/li&gt;
&lt;li&gt;Text that's too small on mobile. 16px is a safe minimum for body text — anything smaller strains readability on phones.&lt;/li&gt;
&lt;li&gt;Forgetting touch targets. Buttons and links need enough padding to be tappable with a thumb — 44px height minimum is the common accessibility guideline.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;final-thoughts-6&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Responsive design isn't a separate skill you learn once and forget — it's a habit you build into every single component from day one. Start mobile-first, use flexible units, test on real devices, and most layout bugs simply won't happen in the first place.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;em&gt;muhammad-farhan-dev.github.io/muhammadfarhan.dev&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22995/responsive-design-101-how-to-make-any-website-mobile-friendly</guid>
<pubDate>Fri, 31 Jul 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>Building a Custom React Hook Library From Scratch (Complete Guide)</title>
<link>https://coderlegion.com/23208/building-a-custom-react-hook-library-from-scratch-complete-guide</link>
<description>&lt;h2 id=&quot;introduction-why-hooks-deserve-this-much-attention&quot;&gt;Introduction: Why Hooks Deserve This Much Attention&lt;/h2&gt;
&lt;p&gt;Before hooks existed, sharing stateful logic between React components meant reaching for Higher-Order Components (HOCs) or the render props pattern — both of which worked, but both of which came with real costs: wrapper hell in your component tree, awkward prop naming collisions, and code that was genuinely harder to trace through. Hooks, introduced in React 16.8, solved this cleanly. A custom hook is nothing more than a JavaScript function whose name starts with use and which is allowed to call other hooks internally. That's the entire technical definition. But the practice of writing good custom hooks — ones that are reusable, predictable, and don't leak implementation details — is a skill that takes deliberate study.&lt;/p&gt;
&lt;p&gt;This article is a complete treatment of that skill. We're not going to stop at three toy examples. We're going to build ten real, production-worthy hooks, understand exactly why each line of each hook exists, cover the TypeScript patterns that make them safe to reuse across a large codebase, learn how to actually test them in isolation, and finish with how to package the whole thing into a publishable npm library. If you read this article fully and rebuild these hooks yourself, you will have a genuinely reusable toolkit you can drop into every project going forward — and more importantly, you'll understand the underlying patterns well enough to design new hooks confidently on your own.&lt;/p&gt;
&lt;h2 id=&quot;part-1-the-rules-of-hooks-and-why-they-exist&quot;&gt;Part 1: The Rules of Hooks, and Why They Exist&lt;/h2&gt;
&lt;p&gt;Before writing custom hooks, you need a proper mental model of why the &quot;Rules of Hooks&quot; exist, not just what they are. The two rules are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Only call hooks at the top level of a function component or another&lt;br&gt;
hook — never inside loops, conditions, or nested functions.&lt;/li&gt;
&lt;li&gt;Only call hooks from React function components or from other custom&lt;br&gt;
hooks — never from regular JavaScript functions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These rules aren't arbitrary style preferences. React tracks hook state using call order. Internally, when your component renders, React walks through your function body and matches each &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, &lt;code&gt;useRef&lt;/code&gt; call to a slot in an internal linked list, purely based on the order they were called in. If you conditionally skip a hook call on one render but not another — for example, wrapping a &lt;code&gt;useState&lt;/code&gt; call in an &lt;code&gt;if&lt;/code&gt; statement — the order shifts, and React can no longer correctly match state to the right slot. The result is corrupted state, hooks reading the wrong values, and bugs that are maddeningly difficult to trace because they only manifest under specific conditional branches.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// This breaks React's internal bookkeeping
function BrokenComponent({ condition }) {
  if (condition) {
    const [value, setValue] = useState(0); // sometimes called, sometimes not
  }
  const [other, setOther] = useState(&quot;&quot;); // slot position shifts depending on `condition`
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Understanding this internal mechanism — rather than just memorizing &quot;don't put hooks in conditionals&quot; — is what lets you debug genuinely confusing hook-related bugs quickly, and it's essential background before writing your own hooks, since a custom hook that internally violates this rule will silently corrupt the state of every component that uses it.&lt;/p&gt;
&lt;h2 id=&quot;part-2-anatomy-of-a-good-custom-hook&quot;&gt;Part 2: Anatomy of a Good Custom Hook&lt;/h2&gt;
&lt;p&gt;A good custom hook has three properties:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It owns its complexity.&lt;/strong&gt; The consumer of the hook shouldn't need to understand &lt;code&gt;useEffect&lt;/code&gt; cleanup timing, &lt;code&gt;AbortController&lt;/code&gt;, or debounce timers to use it correctly. All of that complexity lives inside the hook.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It exposes a minimal, predictable API.&lt;/strong&gt; Ideally a hook returns either a single value, a tuple &lt;code&gt;([value, setter]&lt;/code&gt;, mirroring &lt;code&gt;useState's&lt;/code&gt; own convention), or a small object with clearly named properties. Avoid returning a dozen loosely related values — that's a sign the hook is doing too many unrelated jobs and should be split.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It composes cleanly with other hooks.&lt;/strong&gt; A hook built well can be used inside another custom hook without surprising behavior — this composability is where hooks show their real power over the HOC pattern they replaced.&lt;/p&gt;
&lt;p&gt;With that framework in place, let's build the actual library.&lt;/p&gt;
&lt;h2 id=&quot;part-3-uselocalstorage-state-synced-to-persistent-storage&quot;&gt;Part 3: useLocalStorage — State Synced to Persistent Storage&lt;/h2&gt;
&lt;p&gt;This is one of the most commonly needed custom hooks, and also one of the easiest to get subtly wrong.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useState, useEffect, useCallback } from &quot;react&quot;;

function useLocalStorage(key, initialValue) {
  const readValue = useCallback(() =&amp;gt; {
    if (typeof window === &quot;undefined&quot;) return initialValue; // SSR safety
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.warn(`Error reading localStorage key &quot;${key}&quot;:`, error);
      return initialValue;
    }
  }, [key, initialValue]);

  const [storedValue, setStoredValue] = useState(readValue);

  const setValue = useCallback(
    (value) =&amp;gt; {
      try {
        const valueToStore = value instanceof Function ? value(storedValue) : value;
        setStoredValue(valueToStore);
        if (typeof window !== &quot;undefined&quot;) {
          window.localStorage.setItem(key, JSON.stringify(valueToStore));
          window.dispatchEvent(new StorageEvent(&quot;local-storage&quot;, { key }));
        }
      } catch (error) {
        console.warn(`Error setting localStorage key &quot;${key}&quot;:`, error);
      }
    },
    [key, storedValue]
  );

  useEffect(() =&amp;gt; {
    function handleStorageChange(event) {
      if (event.key &amp;amp;&amp;amp; event.key !== key) return;
      setStoredValue(readValue());
    }
    window.addEventListener(&quot;storage&quot;, handleStorageChange);
    window.addEventListener(&quot;local-storage&quot;, handleStorageChange);
    return () =&amp;gt; {
      window.removeEventListener(&quot;storage&quot;, handleStorageChange);
      window.removeEventListener(&quot;local-storage&quot;, handleStorageChange);
    };
  }, [key, readValue]);

  return [storedValue, setValue];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's walk through exactly why every piece of this exists, because a naive implementation misses several real-world requirements:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSR safety.&lt;/strong&gt; If this hook runs during server-side rendering (Next.js, Remix), &lt;code&gt;window&lt;/code&gt; doesn't exist. The &lt;code&gt;typeof window === &quot;undefined&quot;&lt;/code&gt; check prevents a hard crash during server rendering — a mistake that trips up nearly every beginner writing their first &lt;code&gt;localStorage&lt;/code&gt; hook.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Try/catch around JSON parsing.&lt;/strong&gt; &lt;code&gt;localStorage&lt;/code&gt; can contain corrupted or manually-edited data (a user opening DevTools and typing garbage into storage, or an old schema version from a previous app update). Without the try/catch, a single malformed value crashes the entire hook on mount.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Functional updates&lt;/strong&gt;. Supporting &lt;code&gt;setValue(prev =&amp;gt; prev + 1)&lt;/code&gt;, not just &lt;code&gt;setValue(5)&lt;/code&gt;, mirrors &lt;code&gt;useState's&lt;/code&gt; own API — and it matters because without it, any consumer needing to update based on the previous value has to read &lt;code&gt;storedValue&lt;/code&gt; from a closure that might be stale, exactly the bug class covered in the JavaScript closures article.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-tab synchronization&lt;/strong&gt;. The native &lt;code&gt;storage&lt;/code&gt; event fires in other tabs when localStorage changes — but critically, it does not fire in the same tab that made the change. That's why we manually dispatch a custom &lt;code&gt;local-storage&lt;/code&gt; event after every write, and listen for both events. Without this, opening the same app in two browser tabs and updating a value in one tab wouldn't update the other tab's in-memory state, even though the underlying storage is correctly synced.&lt;/p&gt;
&lt;p&gt;This hook alone demonstrates the core principle from Part 2: all of this complexity — SSR checks, error handling, cross-tab sync — is completely hidden from anyone using the hook. They just write &lt;code&gt;const [theme, setTheme] = useLocalStorage(&quot;theme&quot;, &quot;dark&quot;)&lt;/code&gt; and get correct behavior in every scenario.&lt;/p&gt;
&lt;h2 id=&quot;part-4-usedebounce-and-usedebouncedcallback-two-related-but-different-hooks&quot;&gt;Part 4: useDebounce and useDebouncedCallback — Two Related but Different Hooks&lt;/h2&gt;
&lt;p&gt;Debouncing comes up constantly — search inputs, autosave, resize handlers — but there are actually two distinct patterns worth separating clearly, because conflating them is a common source of confusion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debouncing a value&lt;/strong&gt; (delay reacting to a value until it stops changing):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useDebounce(value, delay = 300) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() =&amp;gt; {
    const timer = setTimeout(() =&amp;gt; setDebouncedValue(value), delay);
    return () =&amp;gt; clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Debouncing a callback function&lt;/strong&gt; (delay the function call itself, useful for things like autosave triggered by an event handler rather than a changing value):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useDebouncedCallback(callback, delay = 300) {
  const timeoutRef = useRef(null);
  const callbackRef = useRef(callback);

  useEffect(() =&amp;gt; {
    callbackRef.current = callback;
  }, [callback]);

  const debouncedFn = useCallback(
    (...args) =&amp;gt; {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
      timeoutRef.current = setTimeout(() =&amp;gt; {
        callbackRef.current(...args);
      }, delay);
    },
    [delay]
  );

  useEffect(() =&amp;gt; {
    return () =&amp;gt; {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
    };
  }, []);

  return debouncedFn;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the &lt;code&gt;callbackRef&lt;/code&gt; pattern here — it's a subtle but important detail. If we captured &lt;code&gt;callback&lt;/code&gt; directly inside &lt;code&gt;debouncedFn's&lt;/code&gt; closure, every time the parent component re-rendered with a new &lt;code&gt;callback&lt;/code&gt; function reference (which happens constantly if the parent doesn't memoize it), our debounce timer logic would use a stale, outdated version of the function. By storing the latest callback in a ref and always reading &lt;code&gt;callbackRef.current&lt;/code&gt; inside the timeout, we guarantee the most recent version of the callback runs, regardless of how many times the component re-rendered while the timer was pending. This ref-for-latest-value pattern is one of the most useful advanced techniques in custom hook design, and it reappears throughout this article.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use which:&lt;/strong&gt; use &lt;code&gt;useDebounce&lt;/code&gt; when you have a value (search input text) and want a component to re-render only after it settles — the search API call pattern from earlier in this series. Use &lt;code&gt;useDebouncedCallback&lt;/code&gt; when you're debouncing an imperative action itself, like an autosave function triggered on every keystroke.&lt;/p&gt;
&lt;h2 id=&quot;part-5-usefetch-data-fetching-with-cancellation-caching-and-retry&quot;&gt;Part 5: useFetch — Data Fetching With Cancellation, Caching, and Retry&lt;/h2&gt;
&lt;p&gt;A production-worthy fetch hook needs to handle more than the happy path.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useFetch(url, options = {}) {
  const [state, setState] = useState({ data: null, loading: true, error: null });
  const optionsRef = useRef(options);
  optionsRef.current = options;

  useEffect(() =&amp;gt; {
    if (!url) return;
    const controller = new AbortController();
    let isMounted = true;

    setState({ data: null, loading: true, error: null });

    fetch(url, { ...optionsRef.current, signal: controller.signal })
      .then((res) =&amp;gt; {
        if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
        return res.json();
      })
      .then((data) =&amp;gt; {
        if (isMounted) setState({ data, loading: false, error: null });
      })
      .catch((err) =&amp;gt; {
        if (err.name === &quot;AbortError&quot;) return; // expected during cleanup, not a real error
        if (isMounted) setState({ data: null, loading: false, error: err });
      });

    return () =&amp;gt; {
      isMounted = false;
      controller.abort();
    };
  }, [url]);

  return state;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three details worth explaining deeply:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AbortController&lt;/code&gt; &lt;strong&gt;and the race condition it prevents&lt;/strong&gt;. Imagine a component that fetches data based on a &lt;code&gt;userId&lt;/code&gt; prop, and that prop changes quickly (a user clicking through a list of profiles rapidly). Without cancellation, if the first fetch (for user A) is slow and the second fetch (for user B) is fast, the second response could arrive first, get set into state, and then the first (now outdated) response for user A arrives afterward and overwrites the correct state with stale data. &lt;code&gt;AbortController&lt;/code&gt; cancels the in-flight request when the effect re-runs (because &lt;code&gt;url&lt;/code&gt; changed) or the component unmounts, preventing this exact race condition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;isMounted&lt;/code&gt; flag alongside&lt;/strong&gt; &lt;code&gt;AbortController&lt;/code&gt;. You might wonder why we need both. &lt;code&gt;AbortController&lt;/code&gt; prevents the fetch from completing, but in some edge cases (particularly with certain fetch polyfills or when the abort happens mid-JSON-parsing), a &lt;code&gt;.then()&lt;/code&gt; callback can still fire after unmount. The &lt;code&gt;isMounted&lt;/code&gt; flag is a defensive backstop against calling &lt;code&gt;setState&lt;/code&gt; on an unmounted component, which React will warn about in the console.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;optionsRef&lt;/code&gt; pattern.&lt;/strong&gt; If we included &lt;code&gt;options&lt;/code&gt; directly in the effect's dependency array, and the consumer passed a new object literal on every render (&lt;code&gt;useFetch(url, { headers: {...} })&lt;/code&gt;), the effect would re-run on every single render, regardless of whether &lt;code&gt;url&lt;/code&gt; actually changed — a very common and very subtle bug. By storing &lt;code&gt;options&lt;/code&gt; in a ref and reading &lt;code&gt;optionsRef.current&lt;/code&gt; inside the effect, we decouple the effect's re-run condition (only &lt;code&gt;url&lt;/code&gt; changing) from unstable object references passed by the consumer.&lt;/p&gt;
&lt;h2 id=&quot;part-6-usetoggle-simple-but-illustrates-a-design-principle&quot;&gt;Part 6: useToggle — Simple, But Illustrates a Design Principle&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);

  const toggle = useCallback(() =&amp;gt; setValue((v) =&amp;gt; !v), []);
  const setTrue = useCallback(() =&amp;gt; setValue(true), []);
  const setFalse = useCallback(() =&amp;gt; setValue(false), []);

  return [value, { toggle, setTrue, setFalse }];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This hook is intentionally simple, but the return shape teaches an important design lesson: returning &lt;code&gt;[value, actions]&lt;/code&gt; — an array with a value and an object of related actions — is a clean, extensible pattern. Compare this to &lt;code&gt;useState&lt;/code&gt;'s &lt;code&gt;[value, setValue]&lt;/code&gt; tuple; we're following the same convention while accommodating more than one action, without needing a five-element array where the consumer has to remember positional ordering.&lt;/p&gt;
&lt;h2 id=&quot;part-7-usemediaquery-responsive-logic-in-javascript&quot;&gt;Part 7: useMediaQuery — Responsive Logic in JavaScript&lt;/h2&gt;
&lt;p&gt;Sometimes CSS media queries aren't enough — you need to conditionally render entirely different components based on screen size, not just different styles.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useMediaQuery(query) {
  const [matches, setMatches] = useState(() =&amp;gt; {
    if (typeof window === &quot;undefined&quot;) return false;
    return window.matchMedia(query).matches;
  });

  useEffect(() =&amp;gt; {
    const mediaQueryList = window.matchMedia(query);
    const listener = (event) =&amp;gt; setMatches(event.matches);

    setMatches(mediaQueryList.matches); // sync in case it changed between render and effect
    mediaQueryList.addEventListener(&quot;change&quot;, listener);

    return () =&amp;gt; mediaQueryList.removeEventListener(&quot;change&quot;, listener);
  }, [query]);

  return matches;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Navigation() {
  const isMobile = useMediaQuery(&quot;(max-width: 767px)&quot;);
  return isMobile ? &amp;lt;MobileMenu /&amp;gt; : &amp;lt;DesktopMenu /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lazy initializer in &lt;code&gt;useState&lt;/code&gt; again avoids a server/client mismatch — computing &lt;code&gt;window.matchMedia&lt;/code&gt; eagerly during the initial render would crash during SSR, exactly the same class of problem we solved in &lt;code&gt;useLocalStorage&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;part-8-useintersectionobserver-lazy-loading-and-scroll-triggered-animation&quot;&gt;Part 8: useIntersectionObserver — Lazy Loading and Scroll-Triggered Animation&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;function useIntersectionObserver(options = {}) {
  const [entry, setEntry] = useState(null);
  const elementRef = useRef(null);

  useEffect(() =&amp;gt; {
    const node = elementRef.current;
    if (!node) return;

    const observer = new IntersectionObserver(([observedEntry]) =&amp;gt; {
      setEntry(observedEntry);
    }, options);

    observer.observe(node);
    return () =&amp;gt; observer.disconnect();
  }, [options.threshold, options.root, options.rootMargin]);

  return [elementRef, entry];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage for lazy-loading an image only when it scrolls into view:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function LazyImage({ src, alt }) {
  const [ref, entry] = useIntersectionObserver({ threshold: 0.1 });
  const isVisible = entry?.isIntersecting;

  return (
    &amp;lt;div ref={ref}&amp;gt;
      {isVisible ? &amp;lt;img src={src} alt={alt} /&amp;gt; : &amp;lt;div className=&quot;h-48 bg-slate-800&quot; /&amp;gt;}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This hook is a genuinely good example of hiding real complexity: the &lt;code&gt;IntersectionObserver&lt;/code&gt; API itself is imperative and callback-based, entirely foreign to React's declarative style. Wrapping it in a hook translates that imperative browser API into a clean piece of derived state (&lt;code&gt;entry&lt;/code&gt;) that a component can simply read.&lt;/p&gt;
&lt;h2 id=&quot;part-9-useeventlistener-a-general-purpose-dom-event-hook&quot;&gt;Part 9: useEventListener — A General-Purpose DOM Event Hook&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;function useEventListener(eventName, handler, element = window) {
  const savedHandler = useRef(handler);

  useEffect(() =&amp;gt; {
    savedHandler.current = handler;
  }, [handler]);

  useEffect(() =&amp;gt; {
    const targetElement = element?.current ?? element;
    if (!targetElement?.addEventListener) return;

    const eventListener = (event) =&amp;gt; savedHandler.current(event);
    targetElement.addEventListener(eventName, eventListener);

    return () =&amp;gt; targetElement.removeEventListener(eventName, eventListener);
  }, [eventName, element]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses the same &lt;code&gt;savedHandler&lt;/code&gt; ref-for-latest-value pattern from &lt;code&gt;useDebouncedCallback&lt;/code&gt; — critical here because otherwise, every time the consuming component re-renders with a new inline handler function (&lt;code&gt;() =&amp;gt; {...}&lt;/code&gt; defined directly in JSX, a very common pattern), the effect would tear down and re-attach the event listener on every single render, which is both wasteful and, in rare cases involving rapid re-renders, can cause missed events during the brief window of removal and re-attachment.&lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function ResizeAwareComponent() {
  const [width, setWidth] = useState(window.innerWidth);
  useEventListener(&quot;resize&quot;, () =&amp;gt; setWidth(window.innerWidth));
  return &amp;lt;p&amp;gt;Window width: {width}px&amp;lt;/p&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;part-10-useprevious-accessing-the-previous-render-s-value&quot;&gt;Part 10: usePrevious — Accessing the Previous Render's Value&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;function usePrevious(value) {
  const ref = useRef();
  useEffect(() =&amp;gt; {
    ref.current = value;
  });
  return ref.current;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This deceptively small hook is genuinely useful for comparing current and previous props or state — for example, detecting whether a value increased or decreased to conditionally show an &quot;up&quot; or &quot;down&quot; indicator:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function PriceDisplay({ price }) {
  const previousPrice = usePrevious(price);
  const direction = previousPrice != null &amp;amp;&amp;amp; price &amp;gt; previousPrice ? &quot;up&quot; : &quot;down&quot;;
  return &amp;lt;span className={direction === &quot;up&quot; ? &quot;text-green-400&quot; : &quot;text-red-400&quot;}&amp;gt;${price}&amp;lt;/span&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason this works is subtle and worth understanding fully: the &lt;code&gt;useEffect&lt;/code&gt; (with no dependency array, so it runs after every render) updates &lt;code&gt;ref.current&lt;/code&gt; to the current render's value — but effects run after the render completes. So during the render itself, &lt;code&gt;ref.current&lt;/code&gt; still holds whatever was set during the previous render's effect. This timing gap between &quot;what renders&quot; and &quot;when effects run&quot; is exactly what makes &lt;code&gt;usePrevious&lt;/code&gt; work.&lt;/p&gt;
&lt;h2 id=&quot;part-11-typescript-making-the-library-genuinely-safe-to-reuse&quot;&gt;Part 11: TypeScript — Making the Library Genuinely Safe to Reuse&lt;/h2&gt;
&lt;p&gt;A hook library without proper types is significantly less valuable in any serious codebase. Here's &lt;code&gt;useLocalStorage&lt;/code&gt; fully typed with generics:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useLocalStorage&amp;lt;T&amp;gt;(
  key: string,
  initialValue: T
): [T, (value: T | ((prev: T) =&amp;gt; T)) =&amp;gt; void] {
  const readValue = useCallback((): T =&amp;gt; {
    if (typeof window === &quot;undefined&quot;) return initialValue;
    try {
      const item = window.localStorage.getItem(key);
      return item ? (JSON.parse(item) as T) : initialValue;
    } catch {
      return initialValue;
    }
  }, [key, initialValue]);

  const [storedValue, setStoredValue] = useState&amp;lt;T&amp;gt;(readValue);

  const setValue = useCallback(
    (value: T | ((prev: T) =&amp;gt; T)) =&amp;gt; {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    },
    [key, storedValue]
  );

  return [storedValue, setValue];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, &lt;code&gt;useLocalStorage&amp;lt;boolean&amp;gt;(&quot;dark-mode&quot;, false)&lt;/code&gt; correctly infers that the setter only accepts a &lt;code&gt;boolean&lt;/code&gt; or a function returning a &lt;code&gt;boolean&lt;/code&gt; — TypeScript will flag &lt;code&gt;setDarkMode(&quot;yes&quot;)&lt;/code&gt; as an error at compile time, before it ever becomes a runtime bug. This is the exact generics pattern discussed in the TypeScript-for-React article in this series, applied specifically to hook design.&lt;/p&gt;
&lt;h2 id=&quot;part-12-testing-custom-hooks-in-isolation&quot;&gt;Part 12: Testing Custom Hooks in Isolation&lt;/h2&gt;
&lt;p&gt;Hooks can't be called outside a component, which means testing them naively is awkward. The &lt;code&gt;@testing-library/react&lt;/code&gt; package's &lt;code&gt;renderHook&lt;/code&gt; utility solves this cleanly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev @testing-library/react
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;import { renderHook, act } from &quot;@testing-library/react&quot;;
import { useToggle } from &quot;./useToggle&quot;;

test(&quot;useToggle flips the boolean value&quot;, () =&amp;gt; {
  const { result } = renderHook(() =&amp;gt; useToggle(false));

  expect(result.current[0]).toBe(false);

  act(() =&amp;gt; {
    result.current[1].toggle();
  });

  expect(result.current[0]).toBe(true);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;renderHook&lt;/code&gt; mounts your hook inside a minimal, invisible test component internally, giving you &lt;code&gt;result.current&lt;/code&gt; to inspect the hook's return value after each update. The &lt;code&gt;act()&lt;/code&gt; wrapper is required around anything that triggers a state update — it ensures React fully flushes the update before your assertion runs, preventing flaky, timing-dependent test failures.&lt;/p&gt;
&lt;p&gt;Testing &lt;code&gt;useDebounce&lt;/code&gt; requires fake timers, since we don't want tests to actually wait 300ms in real time:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { renderHook } from &quot;@testing-library/react&quot;;
import { useDebounce } from &quot;./useDebounce&quot;;

test(&quot;useDebounce delays the value update&quot;, () =&amp;gt; {
  jest.useFakeTimers();
  const { result, rerender } = renderHook(({ value }) =&amp;gt; useDebounce(value, 300), {
    initialProps: { value: &quot;a&quot; },
  });

  expect(result.current).toBe(&quot;a&quot;);

  rerender({ value: &quot;b&quot; });
  expect(result.current).toBe(&quot;a&quot;); // still old value, timer hasn't fired

  act(() =&amp;gt; jest.advanceTimersByTime(300));
  expect(result.current).toBe(&quot;b&quot;); // now updated

  jest.useRealTimers();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This kind of test is exactly what catches regressions if someone later &quot;simplifies&quot; the hook and accidentally removes the debounce delay entirely — a genuine risk in any shared library as more people contribute to it over time.&lt;/p&gt;
&lt;h2 id=&quot;part-13-composing-hooks-together&quot;&gt;Part 13: Composing Hooks Together&lt;/h2&gt;
&lt;p&gt;The real power of custom hooks shows up when you build higher-level hooks from the primitives you've already written. Here's a &lt;code&gt;useDebouncedSearch&lt;/code&gt; hook built entirely by composing &lt;code&gt;useDebounce&lt;/code&gt; and &lt;code&gt;useFetch&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useDebouncedSearch(query, delay = 400) {
  const debouncedQuery = useDebounce(query, delay);
  const url = debouncedQuery ? `/api/search?q=${encodeURIComponent(debouncedQuery)}` : null;
  return useFetch(url);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three lines, zero new &lt;code&gt;useEffect&lt;/code&gt; calls, zero new cleanup logic — because all of that complexity already lives inside &lt;code&gt;useDebounce&lt;/code&gt; and &lt;code&gt;useFetch&lt;/code&gt;. This composability is the payoff for the careful, encapsulated design discussed throughout this article. A poorly designed hook (one that leaks implementation details or has an awkward API) is painful to compose; a well-designed one nearly disappears into the next layer built on top of it.&lt;/p&gt;
&lt;h2 id=&quot;part-14-common-pitfalls-to-avoid&quot;&gt;Part 14: Common Pitfalls to Avoid&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Forgetting cleanup functions.&lt;/strong&gt; Every &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt;, event listener, or subscription started inside a &lt;code&gt;useEffect&lt;/code&gt; needs a corresponding cleanup in the returned function. Skipping this is the single most common source of memory leaks and &quot;why is this firing twice&quot; bugs in custom hooks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Including unstable references in dependency arrays.&lt;/strong&gt; Passing a new object or array literal on every render, then including it in a &lt;code&gt;useEffect&lt;/code&gt; dependency array, causes the effect to re-run every render regardless of whether the meaningful content actually changed. The &lt;code&gt;optionsRef&lt;/code&gt; pattern from &lt;code&gt;useFetch&lt;/code&gt; is the standard fix.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Returning too much from a single hook.&lt;/strong&gt; If a hook returns eight loosely related values, that's a sign it's actually doing the job of two or three separate hooks and should be split for clarity and reusability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not handling the SSR case.&lt;/strong&gt; Any hook touching &lt;code&gt;window&lt;/code&gt;, &lt;code&gt;document&lt;/code&gt;, or &lt;code&gt;localStorage&lt;/code&gt; needs an explicit guard for server-side rendering environments, or it will crash Next.js/Remix apps during the server render pass.&lt;/p&gt;
&lt;h2 id=&quot;part-15-structuring-and-publishing-the-library&quot;&gt;Part 15: Structuring and Publishing the Library&lt;/h2&gt;
&lt;p&gt;Bringing all ten hooks together into a real, publishable package:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my-hooks/
  src/
    useLocalStorage.ts
    useDebounce.ts
    useDebouncedCallback.ts
    useFetch.ts
    useToggle.ts
    useMediaQuery.ts
    useIntersectionObserver.ts
    useEventListener.ts
    usePrevious.ts
    index.ts
  __tests__/
    useToggle.test.ts
    useDebounce.test.ts
  package.json
  tsconfig.json
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// src/index.ts
export { useLocalStorage } from &quot;./useLocalStorage&quot;;
export { useDebounce } from &quot;./useDebounce&quot;;
export { useDebouncedCallback } from &quot;./useDebouncedCallback&quot;;
export { useFetch } from &quot;./useFetch&quot;;
export { useToggle } from &quot;./useToggle&quot;;
export { useMediaQuery } from &quot;./useMediaQuery&quot;;
export { useIntersectionObserver } from &quot;./useIntersectionObserver&quot;;
export { useEventListener } from &quot;./useEventListener&quot;;
export { usePrevious } from &quot;./usePrevious&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mark React as a peer dependency, not a direct dependency, since the consuming project already has its own React instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;@yourusername/react-hooks&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;peerDependencies&quot;: {
    &quot;react&quot;: &quot;&amp;gt;=16.8.0&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;react&quot;: &quot;^18.0.0&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Building this with &lt;code&gt;tsup&lt;/code&gt; (covered in depth in the npm publishing article in this series) produces both ESM and CommonJS outputs with generated type definitions, ready to &lt;code&gt;npm publish&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;part-15-5-one-more-pattern-useclickoutside&quot;&gt;Part 15.5: One More Pattern — useClickOutside&lt;/h2&gt;
&lt;p&gt;Dropdowns, modals, and popovers almost universally need to close when a user clicks outside their boundary. This is a small hook, but it demonstrates a technique not yet covered: attaching a listener to &lt;code&gt;document&lt;/code&gt; while excluding clicks that originate from inside a specific ref'd element.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useClickOutside(callback) {
  const ref = useRef(null);
  const callbackRef = useRef(callback);

  useEffect(() =&amp;gt; {
    callbackRef.current = callback;
  }, [callback]);

  useEffect(() =&amp;gt; {
    function handleClick(event) {
      if (ref.current &amp;amp;&amp;amp; !ref.current.contains(event.target)) {
        callbackRef.current(event);
      }
    }

    document.addEventListener(&quot;mousedown&quot;, handleClick);
    return () =&amp;gt; document.removeEventListener(&quot;mousedown&quot;, handleClick);
  }, []);

  return ref;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Dropdown({ onClose, children }) {
  const ref = useClickOutside(onClose);
  return &amp;lt;div ref={ref} className=&quot;absolute bg-slate-800 rounded-lg p-2&quot;&amp;gt;{children}&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two details worth calling out. First, &lt;code&gt;mousedown&lt;/code&gt; is used instead of &lt;code&gt;click&lt;/code&gt; — this matters because &lt;code&gt;mousedown&lt;/code&gt; fires before &lt;code&gt;mouseup&lt;/code&gt;/&lt;code&gt;click&lt;/code&gt;, which means if the dropdown's own toggle button is what opened it, using &lt;code&gt;click&lt;/code&gt; could cause a same-click open-then-immediately-close race, since the outside-click handler and the toggle handler might both fire for the same interaction depending on event bubbling order. Using &lt;code&gt;mousedown&lt;/code&gt; avoids this specific timing collision in most real implementations. Second, this hook again uses the &lt;code&gt;callbackRef&lt;/code&gt; latest-value pattern from Part 4 and Part 9 — by this point in the article, this pattern should feel familiar rather than mysterious, which is exactly the goal: once you've internalized why it's needed, you'll recognize the situations that call for it instinctively, rather than needing to look it up each time.&lt;/p&gt;
&lt;h2 id=&quot;part-16-a-real-world-example-building-useform-from-these-primitives&quot;&gt;Part 16: A Real-World Example — Building useForm From These Primitives&lt;/h2&gt;
&lt;p&gt;Let's prove the composability claim with something substantial: a form-handling hook built entirely from patterns already covered in this article, plus a few new ones specific to form state.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useForm(initialValues, validate) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  const [touched, setTouched] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleChange = useCallback((name, value) =&amp;gt; {
    setValues((prev) =&amp;gt; ({ ...prev, [name]: value }));
  }, []);

  const handleBlur = useCallback(
    (name) =&amp;gt; {
      setTouched((prev) =&amp;gt; ({ ...prev, [name]: true }));
      if (validate) {
        const validationErrors = validate(values);
        setErrors(validationErrors);
      }
    },
    [values, validate]
  );

  const handleSubmit = useCallback(
    (onSubmit) =&amp;gt; async (event) =&amp;gt; {
      event.preventDefault();
      const allTouched = Object.keys(values).reduce(
        (acc, key) =&amp;gt; ({ ...acc, [key]: true }),
        {}
      );
      setTouched(allTouched);

      const validationErrors = validate ? validate(values) : {};
      setErrors(validationErrors);

      if (Object.keys(validationErrors).length &amp;gt; 0) return;

      setIsSubmitting(true);
      try {
        await onSubmit(values);
      } finally {
        setIsSubmitting(false);
      }
    },
    [values, validate]
  );

  const reset = useCallback(() =&amp;gt; {
    setValues(initialValues);
    setErrors({});
    setTouched({});
  }, [initialValues]);

  return { values, errors, touched, isSubmitting, handleChange, handleBlur, handleSubmit, reset };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice what this hook does not need to reimplement: debouncing validation calls (it could compose &lt;code&gt;useDebouncedCallback&lt;/code&gt; around the &lt;code&gt;validate&lt;/code&gt; call for expensive async validation), persisting draft form state (it could compose &lt;code&gt;useLocalStorage&lt;/code&gt; to auto-save &lt;code&gt;values&lt;/code&gt; on every change), or detecting whether the form has unsaved changes (it could compose &lt;code&gt;usePrevious&lt;/code&gt; to compare &lt;code&gt;values&lt;/code&gt; against the last saved state). This is the actual payoff of building a hook library methodically instead of writing one-off logic per project: a new, fairly complex piece of functionality like form handling becomes mostly composition, with very little genuinely new code.&lt;/p&gt;
&lt;p&gt;Here's the auto-save composition made concrete:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useAutoSaveForm(initialValues, validate, storageKey) {
  const [draft, setDraft] = useLocalStorage(storageKey, initialValues);
  const form = useForm(draft, validate);

  useEffect(() =&amp;gt; {
    setDraft(form.values);
  }, [form.values]);

  return form;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four lines on top of two existing hooks, and now every form using this pattern automatically persists drafts across page reloads and browser crashes — a feature that would otherwise require careful, hook-specific implementation.&lt;/p&gt;
&lt;h2 id=&quot;part-17-performance-considerations-specific-to-hook-libraries&quot;&gt;Part 17: Performance Considerations Specific to Hook Libraries&lt;/h2&gt;
&lt;p&gt;A few performance details matter more in a shared hook library than in one-off component code, precisely because these hooks will be used dozens or hundreds of times across a real application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stabilize returned functions with &lt;code&gt;useCallback&lt;/code&gt;.&lt;/strong&gt; Every hook in this library that returns a function (&lt;code&gt;toggle&lt;/code&gt;, &lt;code&gt;setValue&lt;/code&gt;, &lt;code&gt;handleChange&lt;/code&gt;) wraps it in &lt;code&gt;useCallback&lt;/code&gt;. This isn't optional polish — if a consuming component passes &lt;code&gt;toggle&lt;/code&gt; down to a &lt;code&gt;React.memo&lt;/code&gt;-wrapped child (the pattern discussed in the React performance article in this series), an unstabilized function reference defeats that child's memoization on every single render of the parent, silently undoing an optimization the consumer thought they had.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid creating new objects in the hook's return value on every render.&lt;/strong&gt; Returning { &lt;code&gt;toggle&lt;/code&gt;, &lt;code&gt;setTrue&lt;/code&gt;, &lt;code&gt;setFalse&lt;/code&gt; } as a fresh object literal on every render (even if the three functions themselves are individually memoized) still creates referential inequality for the object itself, which matters if a consumer passes that whole object as a prop to a memoized child. For hooks with more than one or two returned actions, consider memoizing the returned object itself with &lt;code&gt;useMemo&lt;/code&gt; if you know it's likely to be passed as a single prop elsewhere.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  const toggle = useCallback(() =&amp;gt; setValue((v) =&amp;gt; !v), []);
  const setTrue = useCallback(() =&amp;gt; setValue(true), []);
  const setFalse = useCallback(() =&amp;gt; setValue(false), []);

  const actions = useMemo(() =&amp;gt; ({ toggle, setTrue, setFalse }), [toggle, setTrue, setFalse]);

  return [value, actions];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Be deliberate about effect dependency granularity.&lt;/strong&gt; In &lt;code&gt;useIntersectionObserver&lt;/code&gt;, notice the dependency array uses &lt;code&gt;options.threshold&lt;/code&gt;, &lt;code&gt;options.root&lt;/code&gt;, &lt;code&gt;options.rootMargin&lt;/code&gt; individually rather than the whole &lt;code&gt;options&lt;/code&gt; object. This is intentional — depending on the whole object would cause the observer to be torn down and recreated on every render where the consumer passes a fresh object literal (an extremely common pattern), even when the actual threshold values never changed.&lt;/p&gt;
&lt;h2 id=&quot;frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Should every piece of reusable logic become a custom hook?&lt;/strong&gt; No. If the logic is genuinely only used in one component and unlikely to be reused, extracting it into a separate hook adds an indirection cost without a corresponding reuse benefit. Extract a custom hook once you have a second real use case, or when a single component's logic has grown complex enough that separating it improves readability even without reuse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can custom hooks call other custom hooks?&lt;/strong&gt; Yes, and this is exactly the composability demonstrated in &lt;code&gt;useDebouncedSearch&lt;/code&gt; and &lt;code&gt;useAutoSaveForm&lt;/code&gt; above. This is one of the biggest advantages hooks have over the older HOC pattern, where composing multiple HOCs together created deeply nested wrapper components that were painful to debug in React DevTools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do I need to prefix every internal helper function with &lt;code&gt;use&lt;/code&gt;?&lt;/strong&gt; No — only functions that actually call other hooks internally need the &lt;code&gt;use&lt;/code&gt; prefix, because that's what signals to React's linter (&lt;code&gt;eslint-plugin-react-hooks&lt;/code&gt;) and to other developers that the Rules of Hooks apply to this function. A regular helper function that doesn't call &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, or any other hook should not be prefixed with &lt;code&gt;use&lt;/code&gt;, since doing so misleadingly implies hook rules apply to it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How many hooks are too many for one library?&lt;/strong&gt; There's no fixed number, but organize by domain once you exceed roughly 15-20 hooks — separate packages or clearly divided folders for form-related hooks, data-fetching hooks, and browser/DOM hooks, rather than one flat, unorganized list that becomes hard to discover and document.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Every hook in this library follows the same underlying philosophy: hide complexity, expose a minimal API, and design for composability. Once you've internalized these eleven patterns — persistent state, debouncing (both value and callback variants), safe data fetching with cancellation, responsive queries, intersection observation, general event handling, click-outside detection, and previous-value tracking — you have the actual building blocks needed to solve the vast majority of stateful logic problems that come up in real frontend projects, without reaching for a third-party library every time. And because you understand exactly why each line exists, not just what it does, you're equipped to design entirely new hooks for problems this article never covered, using the same underlying principles: hide the imperative complexity, expose a small and predictable surface area, and make sure the pieces compose cleanly with one another.&lt;/p&gt;
&lt;p&gt;It's also worth connecting this back to the rest of this series deliberately. The &lt;code&gt;AbortController&lt;/code&gt; pattern in &lt;code&gt;useFetch&lt;/code&gt; is the same defensive technique that matters when integrating AI APIs, covered in the chatbot integration article — a slow AI response racing against a component unmount or a rapidly changing conversation ID is exactly the same race condition &lt;code&gt;useFetch&lt;/code&gt; prevents for ordinary data fetching. The TypeScript generics applied to &lt;code&gt;useLocalStorage&lt;/code&gt; here are a direct, practical application of the discriminated-union and generic-component patterns from the TypeScript-for-React article. And the discipline of profiling before optimizing, discussed at length in the React performance article, applies just as much to a shared hook library as it does to individual components — don't add &lt;code&gt;useMemo&lt;/code&gt; around your returned action objects until you've actually confirmed a memoized child is being defeated by referential inequality, rather than adding it reflexively to every hook in the library &quot;just in case.&quot;&lt;/p&gt;
&lt;p&gt;If you build and genuinely use even half of these hooks across a real project, you'll notice a concrete shift in how you approach new features: instead of asking &quot;how do I write this logic,&quot; you'll increasingly ask &quot;which of my existing hooks can I compose to get most of this for free,&quot; which is the actual mark of a mature, well-designed personal toolkit rather than a pile of one-off utility functions.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan. &lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt;  &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Fahan&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23208/building-a-custom-react-hook-library-from-scratch-complete-guide</guid>
<pubDate>Wed, 22 Jul 2026 09:48:19 +0000</pubDate>
</item>
<item>
<title>Why You Are Not Getting Better as a Developer (And Why Courses Won't Fix It)</title>
<link>https://coderlegion.com/16201/why-you-are-not-getting-better-as-a-developer-and-why-courses-wont-fix-it</link>
<description>&lt;h2 id=&quot;the-loop-that-keeps-most-developers-stuck&quot;&gt;&lt;strong&gt;The Loop That Keeps Most Developers Stuck&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You have the courses. You have the bookmarks. You have the &quot;must watch&quot; videos saved to watch later.&lt;/p&gt;
&lt;p&gt;And still. You are not improving.&lt;/p&gt;
&lt;p&gt;Not in any way that actually shows up in your work or your confidence.&lt;/p&gt;
&lt;p&gt;Here is the hard truth. It was never a knowledge problem.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-cycle-you-cannot-break&quot;&gt;&lt;strong&gt;The Cycle You Cannot Break&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;It starts the same way every time.&lt;/p&gt;
&lt;p&gt;New course. New energy. New plan.&lt;/p&gt;
&lt;p&gt;You tell yourself, &quot;This time I am doing it properly.&quot;&lt;/p&gt;
&lt;p&gt;Day one is focused. Day two is still good. Day three gets busy. Day four you skip. Day five you tell yourself you will restart next week.&lt;/p&gt;
&lt;p&gt;And just like that, you are back to scrolling and watching. You are &quot;learning&quot; but not really building.&lt;/p&gt;
&lt;p&gt;Weeks pass. Sometimes months.&lt;/p&gt;
&lt;p&gt;The worst part is that you already know what to do. That is what makes it so frustrating.&lt;/p&gt;
&lt;p&gt;Why Another Course Will Not Save You&lt;br&gt;
Most developers think they need a better course or a different tech stack. They think they are not ready yet.&lt;/p&gt;
&lt;p&gt;But deep down, you already know the truth.&lt;/p&gt;
&lt;p&gt;Every time you actually sat down and wrote code, even for 30 minutes, you made progress. Small progress. But real progress.&lt;/p&gt;
&lt;p&gt;The problem is not learning. The problem is showing up consistently enough for that learning to compound.&lt;/p&gt;
&lt;p&gt;You do not get better with six hour binge sessions once a month. You get better with 20 minutes every day, even when it feels boring.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-uncomfortable-realization&quot;&gt;&lt;strong&gt;The Uncomfortable Realization&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Here is what no one really emphasizes.&lt;/p&gt;
&lt;p&gt;Consistency is not exciting. It is repetitive. Quiet. Sometimes frustrating.&lt;/p&gt;
&lt;p&gt;But it is the only thing that works.&lt;/p&gt;
&lt;p&gt;Intense sprints feel productive, but they do not build real skill. Small daily actions do, because they force your brain to rewire instead of just cramming information.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-consistency-feels-so-hard&quot;&gt;&lt;strong&gt;Why Consistency Feels So Hard&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The advice sounds simple. Just code every day.&lt;/p&gt;
&lt;p&gt;But in reality, you run into specific problems.&lt;/p&gt;
&lt;p&gt;You do not know what to work on each day. You overthink which topic to learn next. You set goals that are too big. You lose all momentum after missing just one day.&lt;/p&gt;
&lt;p&gt;So you end up trapped in the same loop.&lt;/p&gt;
&lt;p&gt;Start. Stop. Restart. Repeat.&lt;/p&gt;
&lt;p&gt;And every restart feels heavier than the last.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-actually-helps&quot;&gt;&lt;strong&gt;What Actually Helps&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;At Coder Legion, we stopped thinking in terms of &quot;I need to improve.&quot;&lt;/p&gt;
&lt;p&gt;Instead, we started thinking, &quot;I need a system that makes showing up easy.&quot;&lt;/p&gt;
&lt;p&gt;Not perfect. Just easy.&lt;/p&gt;
&lt;p&gt;A system that removes decision fatigue, overthinking, and randomness. Because willpower alone does not last. Structure does.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;one-small-shift-that-changes-everything&quot;&gt;&lt;strong&gt;One Small Shift That Changes Everything&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Stop telling yourself, &quot;I will study when I have time.&quot;&lt;/p&gt;
&lt;p&gt;Start telling yourself, &quot;This is something I do daily, even if it is just 20 minutes.&quot;&lt;/p&gt;
&lt;p&gt;That shift sounds small, but it changes your identity. You are no longer someone who tries to learn coding. You are someone who shows up consistently.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-part-most-developers-skip&quot;&gt;&lt;strong&gt;The Part Most Developers Skip&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Everyone wants results. Better skills. A better job. More confidence.&lt;/p&gt;
&lt;p&gt;But very few people build the one thing that actually leads there.&lt;/p&gt;
&lt;p&gt;A simple, repeatable system they can stick to. Not for three days. Not for two weeks. But long enough to see real change.&lt;/p&gt;
&lt;p&gt;That is why we built something for the Coder Legion community.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;free-download-for-coder-legion-readers&quot;&gt;&lt;strong&gt;Free Download For Coder Legion Readers&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The 30 Day Coding Consistency Tracker&lt;/p&gt;
&lt;p&gt;This tracker gives you a simple daily 20 minute prompt. No decision fatigue. No overthinking. Just show up and code.&lt;/p&gt;
&lt;p&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://yaman95.gumroad.com/l/30-day-junior-developer-reset-system&quot;&gt;Get the free tracker here&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;if-you-feel-stuck-read-this&quot;&gt;&lt;strong&gt;If You Feel Stuck, Read This&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You are not stuck because you are not smart enough. You are not stuck because you chose the wrong path. You are not stuck because you need another course.&lt;/p&gt;
&lt;p&gt;You are stuck because your effort is inconsistent.&lt;/p&gt;
&lt;p&gt;And inconsistent effort does not compound.&lt;/p&gt;
&lt;p&gt;What To Focus On Instead&lt;br&gt;
Do not aim for perfect days.&lt;/p&gt;
&lt;p&gt;Aim for showing up. Aim for doing something small. Aim for not breaking the chain.&lt;/p&gt;
&lt;p&gt;That is it.&lt;/p&gt;
&lt;p&gt;It will not feel impressive at first. But give it a few weeks, and you will notice something.&lt;/p&gt;
&lt;p&gt;You are not restarting anymore. You are progressing.&lt;/p&gt;
&lt;p&gt;That is when things finally start to change.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;your-next-step&quot;&gt;&lt;strong&gt;Your Next Step&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You already know what to learn. You do not need another course.&lt;/p&gt;
&lt;p&gt;You need a system.&lt;/p&gt;
&lt;p&gt;Here is what to do right now.&lt;/p&gt;
&lt;p&gt;Download the free tracker. Commit to 20 minutes today. Put it somewhere visible and mark each day with an X.&lt;/p&gt;
&lt;p&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://yaman95.gumroad.com/l/30-day-junior-developer-reset-system&quot;&gt;Claim your free 30 Day Consistency Tracker from Coder Legion&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No email required. Just the system you have been missing.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/16201/why-you-are-not-getting-better-as-a-developer-and-why-courses-wont-fix-it</guid>
<pubDate>Wed, 29 Apr 2026 15:05:54 +0000</pubDate>
</item>
<item>
<title>Architect's Log: AWS S3 Learning</title>
<link>https://coderlegion.com/15719/architects-log-aws-s3-learning</link>
<description>&lt;p&gt;I’ve been documenting my learning journey with Amazon Web Services—and this time, it’s S3.&lt;br&gt;
Here are a few things that finally clicked for me:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ARCHITECT’S LOG | Episode 09: The Infinite Storage&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;&quot;If AWS is a city, S3 is the warehouse that never runs out of space.&quot; &lt;br&gt;
Before we dive into networking, we have to master Amazon S3 (Simple Storage Service). It’s the backbone of the cloud whether you're hosting a static website, storing logs, or building a massive data lake.&lt;/p&gt;
&lt;p&gt;Here is why S3 is foundational to any architecture:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Buckets &amp;amp; Objects: The Basics&lt;br&gt;
Think of S3 as a global file system:&lt;br&gt;
Buckets: Your root containers. Remember: bucket names must be globally unique across all of AWS!&lt;br&gt;
Objects: Your files. Each object can be up to 5TB, and you can store an unlimited number of them. This can be either as a file name or a folder path + file name. Example: file.txt, folder/file.txt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Durability vs. Availability ️&lt;br&gt;
AWS designed S3 for &quot;11 nines&quot; of durability (99.999999999%). This means your data is effectively &quot;safe for life.&quot; Availability is then managed by choosing the right class to balance speed and cost.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The 6 Storage Classes (The Architect’s Toolkit) &lt;br&gt;
An architect’s job is to optimize cost by matching the data to the right tier:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;S3 Standard: Best for &quot;Hot Data&quot; accessed frequently with millisecond latency.&lt;/p&gt;
&lt;p&gt;S3 Express One Zone: High-performance, single-zone storage for AI/ML workloads requiring single-digit millisecond latency.&lt;/p&gt;
&lt;p&gt;S3 Standard-IA: Infrequent Access; lower cost for data accessed monthly.&lt;/p&gt;
&lt;p&gt;S3 Intelligent-Tiering: The &quot;set it and forget it&quot; tier that automatically moves data to cheaper classes based on access patterns.&lt;/p&gt;
&lt;p&gt;S3 Glacier Instant Retrieval: High-performance archiving for data needed in milliseconds but accessed rarely (e.g., medical records).&lt;/p&gt;
&lt;p&gt;S3 Glacier Deep Archive: The ultimate low-cost option for long-term compliance data that can take 12–48 hours to retrieve.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Security: Locked Down &lt;br&gt;
By default, all new buckets are private. We use Bucket Policies for resource-level access and IAM Policies for user-level permissions to ensure only the right identities touch our data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/posts/opeyemi-ogunsanya_aws-cloudarchitecture-s3-share-7453292163850829824-nMEC&quot;&gt;https://www.linkedin.com/posts/opeyemi-ogunsanya_aws-cloudarchitecture-s3-share-7453292163850829824-nMEC&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If this was helpful, feel free to react so I know to share more like this , it's also on &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/posts/opeyemi-ogunsanya_aws-cloudarchitecture-s3-share-7453292163850829824-nMEC&quot;&gt;linkedin&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15719/architects-log-aws-s3-learning</guid>
<pubDate>Fri, 24 Apr 2026 10:30:51 +0000</pubDate>
</item>
<item>
<title> Python for Absolute Beginners: From Zero to Writing Real Code</title>
<link>https://coderlegion.com/12015/python-for-absolute-beginners-from-zero-to-writing-real-code</link>
<description>&lt;h2 id=&quot;python-for-absolute-beginners-from-zero-to-writing-real-code&quot;&gt;Python for Absolute Beginners: From Zero to Writing Real Code&lt;/h2&gt;
&lt;p&gt;Python is one of the simplest and most powerful programming languages ever created.&lt;br&gt;
If you’re new to programming, &lt;strong&gt;Python is the best place to start&lt;/strong&gt;—not because it’s “easy”, but because it lets you focus on &lt;strong&gt;thinking&lt;/strong&gt;, not fighting syntax.&lt;/p&gt;
&lt;p&gt;This tutorial assumes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ No coding experience&lt;/li&gt;
&lt;li&gt;❌ No computer science background&lt;/li&gt;
&lt;li&gt;✅ Curiosity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s begin.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-what-is-python-really-&quot;&gt;1. What Is Python, Really?&lt;/h3&gt;
&lt;p&gt;Python is a &lt;strong&gt;high-level programming language&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You write instructions in &lt;strong&gt;human-readable English-like syntax&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Python translates them into something the computer understands&lt;/li&gt;
&lt;li&gt;You don’t need to manage memory, registers, or hardware&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;Hello, world!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a real program.&lt;/p&gt;
&lt;p&gt;Python is used in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web development&lt;/li&gt;
&lt;li&gt;AI &amp;amp; Machine Learning&lt;/li&gt;
&lt;li&gt;Automation &amp;amp; scripting&lt;/li&gt;
&lt;li&gt;Data science&lt;/li&gt;
&lt;li&gt;Game development&lt;/li&gt;
&lt;li&gt;Cybersecurity&lt;/li&gt;
&lt;li&gt;Scientific research&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-installing-python&quot;&gt;2. Installing Python&lt;/h3&gt;
&lt;h4 id=&quot;windows-macos-linux&quot;&gt;Windows / macOS / Linux&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;python.org&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Download &lt;strong&gt;Python 3.x&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;During installation (important!):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Check &lt;strong&gt;“Add Python to PATH”&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;check-installation&quot;&gt;Check installation&lt;/h4&gt;
&lt;p&gt;Open terminal / command prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If it prints something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Python 3.12.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’re ready.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-your-first-python-program&quot;&gt;3. Your First Python Program&lt;/h3&gt;
&lt;p&gt;Create a file called:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hello.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Write this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;Hello, Python!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python hello.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; You just executed your first Python program.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-how-python-thinks-very-important-&quot;&gt;4. How Python Thinks (Very Important)&lt;/h3&gt;
&lt;p&gt;Python executes code &lt;strong&gt;line by line&lt;/strong&gt;, from top to bottom.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;First&quot;)
print(&quot;Second&quot;)
print(&quot;Third&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;First
Second
Third
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no magic.&lt;br&gt;
Just instructions.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-variables-storing-information&quot;&gt;5. Variables: Storing Information&lt;/h3&gt;
&lt;p&gt;A variable is a &lt;strong&gt;label&lt;/strong&gt; for data.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;age = 18
name = &quot;Prasoon&quot;
height = 5.9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Python automatically understands the type.&lt;/p&gt;
&lt;h4 id=&quot;common-data-types&quot;&gt;Common data types&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;int     # whole numbers → 1, 10, -3
float   # decimal numbers → 3.14
str     # text → &quot;hello&quot;
bool    # True or False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;is_student = True
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;6-printing-and-input&quot;&gt;6. Printing and Input&lt;/h3&gt;
&lt;h4 id=&quot;printing-values&quot;&gt;Printing values&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;name = &quot;Alex&quot;
print(name)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;taking-input-from-user&quot;&gt;Taking input from user&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;name = input(&quot;Enter your name: &quot;)
print(&quot;Hello&quot;, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⚠️ &lt;code&gt;input()&lt;/code&gt; &lt;strong&gt;always returns a string&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Convert when needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;age = int(input(&quot;Enter your age: &quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;7-basic-math-in-python&quot;&gt;7. Basic Math in Python&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;a = 10
b = 3

print(a + b)   # addition
print(a - b)   # subtraction
print(a * b)   # multiplication
print(a / b)   # division
print(a // b)  # floor division
print(a % b)   # remainder
print(a ** b)  # power
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;8-conditions-making-decisions&quot;&gt;8. Conditions: Making Decisions&lt;/h3&gt;
&lt;p&gt;Python uses &lt;strong&gt;if, elif, else&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;age = int(input(&quot;Enter your age: &quot;))

if age &amp;gt;= 18:
    print(&quot;You are an adult&quot;)
else:
    print(&quot;You are a minor&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;important-rule&quot;&gt;Important rule&lt;/h4&gt;
&lt;p&gt;Python uses &lt;strong&gt;indentation&lt;/strong&gt;, not brackets &lt;code&gt;{}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;❌ Wrong:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;if age &amp;gt; 10:
print(&quot;Hi&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ Correct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;if age &amp;gt; 10:
    print(&quot;Hi&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;9-loops-repeating-work&quot;&gt;9. Loops: Repeating Work&lt;/h3&gt;
&lt;h4 id=&quot;for-loop&quot;&gt;for loop&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;for i in range(5):
    print(i)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0
1
2
3
4
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;while-loop&quot;&gt;while loop&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;count = 0

while count &amp;lt; 5:
    print(count)
    count += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;while&lt;/code&gt; when you &lt;strong&gt;don’t know&lt;/strong&gt; how many times you’ll loop.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;10-lists-storing-multiple-values&quot;&gt;10. Lists: Storing Multiple Values&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;numbers = [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;access-items&quot;&gt;Access items&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(numbers[0])   # first element
print(numbers[-1])  # last element
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;modify-list&quot;&gt;Modify list&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;numbers.append(6)
numbers.remove(3)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;loop-through-list&quot;&gt;Loop through list&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;for num in numbers:
    print(num)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;11-dictionaries-key-value-data&quot;&gt;11. Dictionaries: Key–Value Data&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;student = {
    &quot;name&quot;: &quot;Aarav&quot;,
    &quot;age&quot;: 17,
    &quot;grade&quot;: &quot;A&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Access values:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(student[&quot;name&quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add new key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;student[&quot;city&quot;] = &quot;Delhi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;12-functions-reusable-code&quot;&gt;12. Functions: Reusable Code&lt;/h3&gt;
&lt;p&gt;Functions prevent repetition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def greet(name):
    print(&quot;Hello&quot;, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Call it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;greet(&quot;Prasoon&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With return value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def add(a, b):
    return a + b

result = add(3, 5)
print(result)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;13-errors-are-normal-don-t-panic-&quot;&gt;13. Errors Are Normal (Don’t Panic)&lt;/h3&gt;
&lt;p&gt;Example error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(x)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NameError: name 'x' is not defined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python tried&lt;/li&gt;
&lt;li&gt;It failed&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;told you exactly why&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Errors are teachers, not enemies.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;14-simple-real-project-number-guessing-game&quot;&gt;14. Simple Real Project: Number Guessing Game&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import random

secret = random.randint(1, 10)

while True:
    guess = int(input(&quot;Guess a number (1–10): &quot;))

    if guess == secret:
        print(&quot;Correct! &quot;)
        break
    else:
        print(&quot;Try again&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;variables&lt;/li&gt;
&lt;li&gt;loops&lt;/li&gt;
&lt;li&gt;conditions&lt;/li&gt;
&lt;li&gt;input/output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You’re officially programming.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;15-what-to-learn-next&quot;&gt;15. What to Learn Next&lt;/h3&gt;
&lt;p&gt;After this tutorial:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn &lt;strong&gt;modules &amp;amp; packages&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Learn &lt;strong&gt;file handling&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Learn &lt;strong&gt;OOP (classes &amp;amp; objects)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick a direction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web → Flask / Django&lt;/li&gt;
&lt;li&gt;Data → Pandas / NumPy&lt;/li&gt;
&lt;li&gt;Automation → Scripts&lt;/li&gt;
&lt;li&gt;AI → PyTorch / TensorFlow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-advice-read-this-twice-&quot;&gt;Final Advice (Read This Twice)&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;Don’t chase languages.&lt;br&gt;
Chase &lt;strong&gt;thinking clearly&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Python is not just a tool—it’s a way to train your mind to break problems into logic.&lt;/p&gt;
&lt;p&gt;Write bad code.&lt;br&gt;
Break things.&lt;br&gt;
Fix them.&lt;/p&gt;
&lt;p&gt;That’s how programmers are born.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/12015/python-for-absolute-beginners-from-zero-to-writing-real-code</guid>
<pubDate>Sat, 21 Feb 2026 13:16:05 +0000</pubDate>
</item>
<item>
<title>Integrating Third Party APIs Made Easy</title>
<link>https://coderlegion.com/11949/integrating-third-party-apis-made-easy</link>
<description>&lt;p&gt;Integrating third-party APIs can breathe new life into your applications, making them more dynamic and engaging. Whether you're pulling in weather data, payment processing, or social media feeds, using these APIs effectively can elevate your project. This tutorial will walk you through the essential steps for integrating and utilizing third-party APIs with a focus on simplicity and practicality.&lt;/p&gt;
&lt;h4 id=&quot;understanding-apis&quot;&gt;Understanding APIs&lt;/h4&gt;
&lt;p&gt;APIs (Application Programming Interfaces) allow different software applications to communicate. Using a third-party API means you're leveraging the capabilities of another service, saving time and effort in development.&lt;/p&gt;
&lt;h4 id=&quot;selecting-the-right-api&quot;&gt;Selecting the Right API&lt;/h4&gt;
&lt;p&gt;Before you start coding, choose an API that suits your project’s needs. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Weather APIs&lt;/strong&gt; like OpenWeatherMap for real-time weather updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Social Media APIs&lt;/strong&gt; like Twitter API for user engagement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Payment APIs&lt;/strong&gt; like Stripe for hassle-free transactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;getting-access&quot;&gt;Getting Access&lt;/h4&gt;
&lt;p&gt;Most APIs require an API key for authentication. This is usually found in your account settings on the API provider's website. Always keep this key secure to prevent unauthorized access.&lt;/p&gt;
&lt;h4 id=&quot;making-requests&quot;&gt;Making Requests&lt;/h4&gt;
&lt;p&gt;Once you've obtained your API key, you can start making calls to the API. Here is a simple example of how to fetch weather data using &lt;code&gt;fetch&lt;/code&gt; in JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const apiKey = 'YOUR_API_KEY';
const city = 'London';

fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&amp;amp;appid=${apiKey}`)
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; {
    console.log(`Temperature in ${city}: ${data.main.temp}K`);
  })
  .catch(error =&amp;gt; console.error('Error fetching data:', error));
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;parsing-responses&quot;&gt;Parsing Responses&lt;/h4&gt;
&lt;p&gt;APIs typically return data in JSON format. Use JavaScript's &lt;code&gt;JSON.parse&lt;/code&gt; to convert the response into an object you can work with. This will allow you to manipulate or display the data as needed.&lt;/p&gt;
&lt;h4 id=&quot;handling-errors&quot;&gt;Handling Errors&lt;/h4&gt;
&lt;p&gt;Don't forget to handle errors gracefully. APIs can fail for various reasons, including exceeding usage limits or incorrect parameters. Implementing basic error handling ensures a better user experience.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;if (!response.ok) {
  throw new Error('Network response was not ok');
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;practical-example&quot;&gt;Practical Example&lt;/h4&gt;
&lt;p&gt;Suppose you're building a random quote generator. You might use the They Said So Quotes API. Here’s how you’d integrate it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;fetch('https://quotes.rest/qod')
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; {
    const quote = data.contents.quotes[0].quote;
    console.log(`Random Quote: ${quote}`);
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Integrating third-party APIs doesn’t have to be daunting. By following these steps, you can enhance your applications with dynamic functionalities. Always test your integration thoroughly and refer back to API documentation for advanced options. Happy coding! &lt;/p&gt;
&lt;p&gt;Feel free to ask any questions or share your experiences with API integrations below. Let's make our apps chill and engaging together!&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/11949/integrating-third-party-apis-made-easy</guid>
<pubDate>Fri, 20 Feb 2026 17:45:43 +0000</pubDate>
</item>
<item>
<title>Understanding Awaitables: Coroutines, Tasks, and Futures in Python</title>
<link>https://coderlegion.com/1644/understanding-awaitables-coroutines-tasks-and-futures-in-python</link>
<description>&lt;p&gt;Previously, we explored &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/jeffrey04/how-to-write-an-asyncio-telegram-bot-in-python-4hig&quot;&gt;chatbot building with AsyncIO&lt;/a&gt;. As I am committing to publish one article a week, I am constantly on the lookout for new ideas. Then I figured it may be a good opportunity to delve deeper into asynchronous programming. The writing plan eventually expanded to a series of articles, and we are starting with the concept of Awaitables today.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/1*3uPI39CkDzqkT6OJUya19Q.jpeg&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;An illustration from copilot on the topic&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To a lot of us, our first exposure to something resembles asynchronous programming would be learning to write GUI applications. A graphical application usually responds to user events, that may happen any time while it is running. We then attach a handler function to events we are interested in, however we do not have much control when it is executed.&lt;/p&gt;
&lt;h4 id=&quot;the-javascript-prelude-from-callbacks-to-promises&quot;&gt;The JavaScript Prelude: From Callbacks to Promises&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*RUsKxXI9tspcg5ee&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Womanizer Toys on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I first learned programming when I was in college. The assignments were designed to train us to write code with a set of a controlled scope. I graduated in the era of web 2.0, that’s when people started to explore AJAX to add dynamic behaviour to web pages. Suddenly, despite we were plagued with inconsistencies among browser’s JavaScript implementation, webpages started to feel like a GUI application.&lt;/p&gt;
&lt;p&gt;AJAX, which is a short for Asynchronous JavaScript and XML, opens up the possibility for us to fetch data from a web server through JavaScript. With proper use, we can get a page to fetch additional information to update the page content, responding to various events defined in the document object model, DOM. Some examples of DOM events are, clicking on elements in page, elements loaded in page, or even timed events through setInterval and setTimeout.&lt;/p&gt;
&lt;p&gt;Despite having some experience with GUI application programming, but doing it in real enterprise setting feels very different. I was still too used to structured procedural programming, where code execution is often synchronous, in a mostly predictable order. However, when it comes to an enterprise setting, the requirements are constantly changing and time is often a luxury we cannot afford. Despite having good mentor, it still took me quite a while to have a basic grasp of asychronous programming with the delicate language construct at the time.&lt;/p&gt;
&lt;p&gt;Let's start with event handlers. Everything we see in a web page, is represented in a Document Object Model (DOM) tree, and each element is capable of responding to events. For instance, we can click on a button, and have it pop up an alert dialog through a code snippet below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# In HTML markup
&amp;lt;button id=&quot;theButton&quot;&amp;gt;The button&amp;lt;/button&amp;gt;

# In JavaScript
const button = document.getElementById(&quot;theButton&quot;)
button.addEventListener((e) =&amp;gt; window.alert(&quot;Button is pressed&quot;))

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we have callbacks, which were popularized by AJAX calls. Back then, with &lt;a rel=&quot;nofollow&quot; href=&quot;https://jquery.com/&quot;&gt;jQuery&lt;/a&gt;, we could define handlers to deal with both success or failure cases. For instance, let's say we want to fetch the HTML markup of this blog (skipping error failure callback for brevity), we do&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$.ajax({
    url: &quot;https://kitfucoda.medium.com/&quot;,
    success: (data, status, xhr) =&amp;gt; { /* process data here */ }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is worth noticing that both the event handler and the success callback we defined earlier, can only access variables that were defined before their definition. The handler and callback would have no access to new external variables. On the other hand, the code outside the callback and handler do not have access to variables within them. Essentially, we can treat the code being executed separately, completely breaking off from the normal execution flow. Therefore, we do not have a way to tell if they are executed, or when they are done (or failed).&lt;/p&gt;
&lt;p&gt;It is also possible to combine the two together. For example, combining the two examples above, we can make the page to fetch this blog after clicking on the button.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;button.addEventListener(
    (e) =&amp;gt; $.ajax({
        url: 'https://kitfucoda.medium.com',
        success: (data, status, xhr) =&amp;gt; { /* maybe populate this somewhere */ }
    })
)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember we talked about how it is not possible to know if these handlers are done executing from the outside? Yes, nesting them was the only way to ensure order. If you need to fetch my other blog &lt;a rel=&quot;nofollow&quot; href=&quot;https://cslai.coolsilon.com&quot;&gt;https://cslai.coolsilon.com&lt;/a&gt; AFTER finishing fetching this blog, you can do another $.ajax call within the success handler above. The growing nested callbacks eventually led to what people call a callback hell or pyramid of doom.&lt;/p&gt;
&lt;p&gt;I didn’t follow the development of JavaScript much, as I moved on to doing Python. However we eventually had Promise, and my first encounter with it was again through jQuery. Now, it is possible to write a sequence of AJAX calls in a chain, instead of nesting endlessly. For instance&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$.ajax({url: 'https://kitfucoda.medium.com/'})
    .then((response) =&amp;gt; {
        // do something with the response
        // Now start a new ajax
        return $.ajax({url: 'https://cslai.coolsilon.com/'})
    })
    .then((response) =&amp;gt; {
        // Do other thing with the response
    })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No more pyramid of doom, but the callback and the code outside of it still remained separate and independent to each other.&lt;/p&gt;
&lt;h4 id=&quot;enter-asyncio-awaitables-defined&quot;&gt;Enter AsyncIO: Awaitables Defined&lt;/h4&gt;
&lt;p&gt;My exploration of asynchronous programming in Python, was just as chaotic. When I was working for a company that offers CDN service, I spent some time learning about &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.gevent.org/&quot;&gt;gevent and greenlets&lt;/a&gt;. It was practically my first introduction to the asynchronous world in the language. However, I left the company soon after that and didn’t have a chance to see it in action. Years later, I hacked a chatbot that barely worked, and also did a quick exercise &lt;a rel=&quot;nofollow&quot; href=&quot;https://cslai.coolsilon.com/2024/10/14/building-a-simple-asgi-websocket-application/&quot;&gt;building an ASGI websocket chatroom&lt;/a&gt;, without use of any frameworks. While I managed to do it, but it wasn’t a useful introduction to AsyncIO.&lt;/p&gt;
&lt;p&gt;This article, like the one I did on chatbot, is an article I wished I read back then.&lt;/p&gt;
&lt;h5 id=&quot;coroutines-the-foundation-of-awaitables&quot;&gt;Coroutines: The Foundation of Awaitables&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*cYxirWUqp9vR5x23&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Kelly Sikkema on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a prologue to the article I am writing next week, we cover &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.python.org/3/library/asyncio-task.html#awaitables&quot;&gt;Awaitables&lt;/a&gt; this week in the context of AsyncIO. Understanding what they are is core to understanding how to program with AsyncIO. However, before we start, let’s talk about coroutines. A coroutine is a function defined with an async keyword. Note that if a function has any async or await statement, it has to be defined as a coroutine.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# a normal coroutine
async def a_coroutine():
    return 42

# this is invalid
def this_should_be_a_coroutine():
    await some_awaitable()
    return 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We often write functions doing heavy IO-bound work as coroutines, such that other CPU bound computation can still take place simultaneously. To execute these coroutines, we would need an event loop. Despite the name, I prefer seeing it as a timetable like structure, a place where it accepts Awaitables (like coroutines) to be scheduled to run.&lt;/p&gt;
&lt;p&gt;Let’s slowly build a fictional project, as a tool to explore more about asyncio in this series of articles. We start by defining a coroutine that simulates I/O operations, and use &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.python-httpx.org/&quot;&gt;httpx&lt;/a&gt; to make HTTP requests. Given a national Pokédex ID, we want to return the name of the corresponding Pokémon.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async def dex(id: int) -&amp;gt; str:
    assert isinstance(id, int)

    async with httpx.AsyncClient() as client:
        response = await client.get(f&quot;https://pokeapi.co/api/v2/pokemon/{id}/&quot;)

        return f&quot;The pokemon with id {id} is {response.json()['name']}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a coroutine is called like how a function is called, it returns a Coroutine object. The returned object is still pending scheduling, hence the code isn’t executed at this point. If the coroutine does not get a chance to run, e.g. when the function calling the coroutine exits, dropping the reference to it.&lt;/p&gt;
&lt;p&gt;The quickest way to fix it is prefixing an await before it. However, like we discussed earlier, if a function contains an await, then it has to be defined as a coroutine with async. Therefore, going asynchronous usually means an all-in commitment. This also means porting code part-by-part to be asynchronous takes enormous effort.&lt;/p&gt;
&lt;p&gt;Using await is a way to schedule a coroutine to the event loop. The behaviour is similar to synchronous programming, it will attempt to start the execution as soon as possible, and will only execute the next line after a result is returned. But there are times we want to have more control, and that’s achieved by turning it to a task.&lt;/p&gt;
&lt;h5 id=&quot;tasks-scheduling-and-managing-coroutines&quot;&gt;Tasks: Scheduling and Managing Coroutines&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*2nJ2XtcsYAO7xII2&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by airfocus on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A task can be created, by passing in the coroutine object to asyncio.create_task. It returns a asyncio.Task object referencing the scheduled coroutine. Some control is offered through the returned Task object, for example we can check if it is done, cancel the execution, or set a callback when done.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; task = asyncio.create_task(dex(6)) 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*LRSH7j5Jmv3qjXGF&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Halfcut Pokemon on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Unlike the await keyword, you can call asyncio.create_task even in a function, as long as an event loop is available and running. However, being an awaitable object, you can also block execution for subsequent statements with an await too, in a coroutine. However, it is typically used when you only want to revisit the state of execution later (or forget about it).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async def foo() -&amp;gt; str:
    task = asyncio.create_task(dex(104)

    # proceed with other work

    return await task 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*mdB_kyfuyeVbxtAf&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Branden Skeli on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;h5 id=&quot;futures-representing-asynchronous-results&quot;&gt;Futures: Representing Asynchronous Results&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*wq076oix0uxpnLSy&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Zulfa Nazer on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Next, we have Futures, which is the parent class of the Task we just discussed. I personally find this tricky to explain, but while preparing for the article, I was informed that a future works the way a callback does (still remember?). Let’s say I have a very badly defined function to calculate nth Fibonacci number to simulate a CPU-bound operation&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def fibonacci(nth: int) -&amp;gt; int:
    assert nth &amp;gt; 0

    result = ()

    for i in count(1):
        match i:
            case 1:
                result = (0,)

            case 2:
                result += (1,)

            case _:
                result = result[1:] + (sum(result),)

    assert len(result) &amp;gt; 0

    return result[-1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Asynchronous programming is useful in scenario with a lot of I/O operations. It ensures concurrency by making it possible for CPU-bound operations to work, while waiting for I/O. However, if a CPU-bound operation is taking forever, it would end up stalling everything else. Hence, it is advisible to throw the work to another thread or process. We can use loop.run_in_executor to create an asyncio.Future object to offload the work to another thread.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;future = (
    asyncio.get_running_loop()
        .run_in_executor(None, partial(fibonacci, 1500))
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first argument can take either a ThreadPoolExecutor or a ProcessPoolExecutor, leave it as None to use the default ThreadPoolExecutor. The second argument takes a callable, we could have rewrite fibonacci with __call__ dunder &lt;a rel=&quot;nofollow&quot; href=&quot;https://kitfucoda.medium.com/the-versatility-of-call-a-python-developers-secret-weapon-a6bff776971a&quot;&gt;as discussed in the previous article&lt;/a&gt;, but using functools.partial is fine.&lt;/p&gt;
&lt;p&gt;Alternatively we can use asyncio.to_thread which is an helpful abstraction to avoid creating a Future ourselves. However, it returns a coroutine, so it has to be awaited, or scheduled as a Task via asyncio.create_task. Also, unlike loop.run_in_executor, we do not get to choose between a ThreadPoolExecutor or ProcessPoolExecutor.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;coro = asyncio.to_thread(fibonacci, 1000)

# Schedule it for execution
asyncio.create_task(coro)

# Or await directly
await coro
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we haven’t show how callbacks are possible with Futures. Let’s write a simpler example on this topic. Suppose we have a coroutine that has to be run concurrently in the background, streaming a file content over the internet, and we are interested in finding the line number of a specific line in it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async def scan_huge_file(future, need_this_line):
    for line_num, line in enumerate(some_huge_file()):
        if line is need_this_line:
            future.set_result(line_num)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, when we schedule the tasks (again, we will dive deeper on this in the next article), we would have done something like this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;loop = asyncio.get_running_loop()
future = loop.create_future()

asyncio.create_task(scan_huge_file(future, 'very critical line'))

# do other high-priority tasks
...

# when we are finally done with other tasks
number = await future 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The callback is done in scan_huge_file, through future.set_result. The function scheduling the coroutine, only checks if a line number is found, after it is done with other tasks. Of course we could have save a reference to the asyncio.create_task, and then make scan_huge_file return the line number so we can await the task, but this is just to show how a callback can be implemented.&lt;/p&gt;
&lt;p&gt;Now we know the three Awaitables, it is time to revisit what it is. As you may have guessed, it is just a term to describe these three types of objects, where we can use await to get the result.&lt;/p&gt;
&lt;h4 id=&quot;python-vs-javascript-comparison&quot;&gt;Python vs. JavaScript: Comparison&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*YtGBGib8QDsfSgtG&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Oleksandr Chumak on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Asynchronous programming in JavaScript modelled the problem very differently, and hence we have a complete different design. We stopped at Promise just now, and we briefly discussed that because it is the root of the implementation.&lt;/p&gt;
&lt;p&gt;AsyncIO is doing a good job abstracting the event loop away from the users. For instance, we only started to call event loop methods, when we were discussing about Futures. The development experience is getting so much better that using await directly to the coroutine, or to the Task (which wraps a coroutine) should be sufficient for most cases.&lt;/p&gt;
&lt;p&gt;OTOH, event loop in JavaScript, at least in browser, is almost completely abstracted away from us.&lt;/p&gt;
&lt;p&gt;A friend came to me a few days ago, complaining how he is confused about asynchronous programming in the language. Why certain asynchronous functions were called with an await but some without. That prompted me to do a quick check on the topic, and I was quite surprised with the discovery. It turns out if I call an asynchronous function without using await, it will be scheduled in the background.&lt;/p&gt;
&lt;p&gt;The discussion session was the main inspiration to this article, sans the Python part. I started with how event handlers led to creation of callbacks, Promise, and ultimately joining the async-await family. Similar to Python, if a function contains any async or await statement in it, then it has to be defined as async.&lt;/p&gt;
&lt;p&gt;While on the surface both share similar syntax, but the underlying implementations are completely different. In Python asynchronous was designed around coroutines, while in JavaScript was through Promise. I hope by weaving examples from both language it helps to clarify doubts on the matter.&lt;/p&gt;
&lt;h4 id=&quot;looking-ahead-more-asyncio&quot;&gt;&lt;strong&gt;Looking Ahead: More AsyncIO&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1024/0*b7OX8Kc-FR_Rm-cg&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;em&gt;Photo by Andrew Ly on Unsplash&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Originally I was about to write on schedule and manage tasks, alongside notes on error handling through a fictional project. However, after planning out the content, just Awaitables alone would be long enough for the week. Hence, we would start building a fictional project next week, and discuss the above mentioned topics. Feel free to subscribe to the email newsletter so you don’t miss it, and leave me messages if I have missed anything today.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I shall write again, next week.&lt;/p&gt;
&lt;p&gt;For transparency, I’d like to acknowledge that while the code and technical explanations presented in this article are entirely my own, I received editorial assistance from a large language model. This collaboration has helped refine the clarity and structure of my writing. If you’re interested in discussing project collaborations or job opportunities, please feel free to reach out to me &lt;a rel=&quot;nofollow&quot; href=&quot;https://kitfucoda.medium.com&quot;&gt;here on Medium&lt;/a&gt; or via &lt;a rel=&quot;nofollow&quot; href=&quot;https://linkedin.com/in/jeffrey04&quot;&gt;my LinkedIn profile&lt;/a&gt;. The article was &lt;a rel=&quot;nofollow&quot; href=&quot;https://kitfucoda.medium.com/understanding-awaitables-coroutines-tasks-and-futures-in-python-a9c12890d20d&quot;&gt;originally published to Medium&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Adv Concepts</category>
<guid isPermaLink="true">https://coderlegion.com/1644/understanding-awaitables-coroutines-tasks-and-futures-in-python</guid>
<pubDate>Mon, 24 Mar 2025 18:58:34 +0000</pubDate>
</item>
</channel>
</rss>