<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hamed Farazi</title>
    <description>The latest articles on DEV Community by Hamed Farazi (@hamedfarazi).</description>
    <link>https://dev.to/hamedfarazi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4067999%2F9c7fd54d-faf4-4322-9ee3-2f6a69327307.jpg</url>
      <title>DEV Community: Hamed Farazi</title>
      <link>https://dev.to/hamedfarazi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hamedfarazi"/>
    <language>en</language>
    <item>
      <title>Burger Atelier — The Burger, Reimagined 🍔</title>
      <dc:creator>Hamed Farazi</dc:creator>
      <pubDate>Tue, 11 Aug 2026 12:21:21 +0000</pubDate>
      <link>https://dev.to/hamedfarazi/burger-atelier-the-burger-reimagined-3fb7</link>
      <guid>https://dev.to/hamedfarazi/burger-atelier-the-burger-reimagined-3fb7</guid>
      <description>&lt;p&gt;This is a submission for Frontend Challenge - Comfort Food Edition, Perfect Landing&lt;/p&gt;

&lt;p&gt;What I Built&lt;/p&gt;

&lt;p&gt;For this challenge, I wanted to take a familiar comfort food and give it a more refined digital experience.&lt;/p&gt;

&lt;p&gt;I built Burger Atelier, a modern landing page centered around the idea of burgers as more than just fast food — they can be crafted, customized, and presented like an experience.&lt;/p&gt;

&lt;p&gt;The goal was to create a landing page that feels polished while keeping the experience simple and intuitive.&lt;/p&gt;

&lt;p&gt;Highlights&lt;br&gt;
🍔 A bold food-focused visual design&lt;br&gt;
📱 Responsive layout across screen sizes&lt;br&gt;
✨ Interactive UI elements and micro-interactions&lt;br&gt;
🎯 Clear calls-to-action and visual hierarchy&lt;br&gt;
♿ Accessibility-conscious structure and interactions&lt;br&gt;
⚡ Modern React-based frontend&lt;br&gt;
🧩 Reusable components and clean project structure&lt;br&gt;
Demo&lt;/p&gt;

&lt;p&gt;🌐 Live Demo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://frontend-challenge-comfort-food-edi-alpha.vercel.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;frontend-challenge-comfort-food-edi-alpha.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;💻 Source Code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HamedFarazi" rel="noopener noreferrer"&gt;
        HamedFarazi
      &lt;/a&gt; / &lt;a href="https://github.com/HamedFarazi/Frontend-Challenge---Comfort-Food-Edition-Perfect-Landing" rel="noopener noreferrer"&gt;
        Frontend-Challenge---Comfort-Food-Edition-Perfect-Landing
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Perfect Landing: Comfort Food
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Burger Atelier&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Premium interactive burger studio for the DEV Community Frontend Challenge — Comfort Food Edition.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install
npm run dev
npm run build&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stack&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;React · TypeScript · Vite · Tailwind CSS v4 · CSS burger craft&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HamedFarazi/Frontend-Challenge---Comfort-Food-Edition-Perfect-Landing" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Journey&lt;/p&gt;

&lt;p&gt;I approached the project by first thinking about how a food brand could communicate its personality through its landing page.&lt;/p&gt;

&lt;p&gt;Instead of treating the page as a collection of sections, I focused on creating a visual flow that guides the user from the hero section toward the menu and the main call-to-action.&lt;/p&gt;

&lt;p&gt;One of the things I enjoyed most was balancing the visual side of the design with practical frontend considerations. A food landing page can easily become visually heavy, so I tried to keep the interactions clear and the content easy to scan.&lt;/p&gt;

&lt;p&gt;Building the project with React also gave me the opportunity to structure the UI into reusable pieces rather than treating the page as one large component.&lt;/p&gt;

&lt;p&gt;What I learned&lt;/p&gt;

&lt;p&gt;This challenge was a good reminder that a polished landing page isn't only about making things look good.&lt;/p&gt;

&lt;p&gt;The small details matter:&lt;/p&gt;

&lt;p&gt;How quickly users understand what the product is&lt;br&gt;
Whether the primary action is obvious&lt;br&gt;
How the layout behaves on smaller screens&lt;br&gt;
Whether interactive elements feel intentional&lt;br&gt;
How accessible the experience remains beneath the visual layer&lt;/p&gt;

&lt;p&gt;I'm particularly happy with how the final design combines a playful food theme with a more premium visual direction.&lt;/p&gt;

&lt;p&gt;What's Next?&lt;/p&gt;

&lt;p&gt;I'd like to continue experimenting with the concept by adding more interactive ordering flows, richer menu interactions, and potentially turning Burger Atelier into a small multi-page restaurant experience.&lt;/p&gt;

&lt;p&gt;Thanks to the Frontend Challenge team for putting together this challenge! 🙌&lt;/p&gt;

&lt;p&gt;Built with React and modern frontend tools.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>frontendchallenge</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🍔 The Perfect Burger — CSS Art</title>
      <dc:creator>Hamed Farazi</dc:creator>
      <pubDate>Tue, 11 Aug 2026 11:25:10 +0000</pubDate>
      <link>https://dev.to/hamedfarazi/the-perfect-burger-css-art-221</link>
      <guid>https://dev.to/hamedfarazi/the-perfect-burger-css-art-221</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2026-07-29"&gt;Frontend Challenge - Comfort Food Edition, CSS Art&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🍔 The Perfect Burger
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Inspiration
&lt;/h3&gt;

&lt;p&gt;For this challenge, I wanted to create something familiar, fun, and comforting: a classic burger.&lt;/p&gt;

&lt;p&gt;Instead of using images or pre-made assets, I decided to build the entire burger from scratch using HTML and CSS.&lt;/p&gt;

&lt;p&gt;Every ingredient is created with CSS, including the buns, lettuce, tomato, onion, melted cheese, and grilled beef patty.&lt;/p&gt;

&lt;p&gt;The goal was to make something that looks like a burger at first glance, but becomes more interesting when you discover that the entire artwork is built with HTML and CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/Hamed-Farazi/embed/pvNXXqQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://frontend-challenge-comfort-food-edi.vercel.app/" rel="noopener noreferrer"&gt;https://frontend-challenge-comfort-food-edi.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Source Code:&lt;/strong&gt; &lt;a href="https://github.com/HamedFarazi/Frontend-Challenge---Comfort-Food-Edition" rel="noopener noreferrer"&gt;https://github.com/HamedFarazi/Frontend-Challenge---Comfort-Food-Edition&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also interact with the burger to reveal and separate its individual ingredients.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🍞 CSS-crafted toasted buns&lt;/li&gt;
&lt;li&gt;🥩 Grilled beef patty with CSS texture&lt;/li&gt;
&lt;li&gt;🧀 Melted cheese with organic drips&lt;/li&gt;
&lt;li&gt;🥬 Layered lettuce&lt;/li&gt;
&lt;li&gt;🍅 CSS tomato slices&lt;/li&gt;
&lt;li&gt;🧅 CSS onion rings&lt;/li&gt;
&lt;li&gt;✨ CSS gradients and shadows&lt;/li&gt;
&lt;li&gt;🎬 Interactive ingredient reveal mode&lt;/li&gt;
&lt;li&gt;🖱️ Hover and 3D interactions&lt;/li&gt;
&lt;li&gt;♿ Keyboard accessible interactions&lt;/li&gt;
&lt;li&gt;📱 Responsive design&lt;/li&gt;
&lt;li&gt;🌓 &lt;code&gt;prefers-reduced-motion&lt;/code&gt; support&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠️ Built With
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;HTML5&lt;/li&gt;
&lt;li&gt;CSS3&lt;/li&gt;
&lt;li&gt;Vanilla JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎨 CSS Techniques
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gradients&lt;/li&gt;
&lt;li&gt;Pseudo-elements&lt;/li&gt;
&lt;li&gt;Clip-path&lt;/li&gt;
&lt;li&gt;CSS transforms&lt;/li&gt;
&lt;li&gt;CSS animations&lt;/li&gt;
&lt;li&gt;Box shadows&lt;/li&gt;
&lt;li&gt;CSS variables&lt;/li&gt;
&lt;li&gt;3D perspective&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;I started this project with a simple idea: create a burger using only HTML and CSS.&lt;/p&gt;

&lt;p&gt;The first version was intentionally simple, but as I worked on it, I focused on making the ingredients feel more organic, dimensional, and visually appetizing.&lt;/p&gt;

&lt;p&gt;The most challenging parts were creating the melted cheese, the grilled texture of the beef patty, and making all of the ingredients feel like they were physically stacked together.&lt;/p&gt;

&lt;p&gt;I used CSS gradients, pseudo-elements, clip-path, transforms, shadows, and animations to create the different ingredients and their textures.&lt;/p&gt;

&lt;p&gt;One of my favorite parts is the interactive reveal mode. Instead of keeping the burger as a static illustration, users can separate the ingredients and see each layer individually.&lt;/p&gt;

&lt;p&gt;This also became a way to demonstrate that the burger is actually built from individual HTML/CSS elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'd like to continue experimenting with CSS-based food illustrations and push the interaction and visual details even further.&lt;/p&gt;

&lt;p&gt;Thanks for checking out my submission! 🍔&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
    </item>
    <item>
      <title>Why (and When) You Should Actually Use useMemo and useCallback</title>
      <dc:creator>Hamed Farazi</dc:creator>
      <pubDate>Tue, 11 Aug 2026 08:29:43 +0000</pubDate>
      <link>https://dev.to/hamedfarazi/why-and-when-you-should-actually-use-usememo-and-usecallback-4ij0</link>
      <guid>https://dev.to/hamedfarazi/why-and-when-you-should-actually-use-usememo-and-usecallback-4ij0</guid>
      <description>&lt;p&gt;If you've spent any time in a React codebase, you've probably seen &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt; sprinkled everywhere — sometimes on every single function and computed value, "just in case." The irony is that this habit often makes an app &lt;em&gt;slower&lt;/em&gt;, not faster, while also making the code harder to read.&lt;/p&gt;

&lt;p&gt;This article is about building an honest mental model for these two hooks: what they actually do under the hood, when they genuinely help, and when they're just noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these hooks actually do
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt; don't make anything "faster" by default. They &lt;strong&gt;cache a value between renders&lt;/strong&gt; and only recompute it when its dependencies change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;computeExpensiveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;useCallback(fn, deps)&lt;/code&gt; is really just &lt;code&gt;useMemo(() =&amp;gt; fn, deps)&lt;/code&gt;. Same mechanism, different return type (a function reference instead of a value).&lt;/p&gt;

&lt;p&gt;Two things matter here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The caching itself has a cost.&lt;/strong&gt; React has to store the previous dependency array, compare it on every render, and hold onto the cached value in memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You only benefit if something downstream actually cares about referential stability or expensive recomputation.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If neither of those is true, you're paying the comparison cost for zero benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The case where it's obviously worth it: expensive computations
&lt;/h2&gt;

&lt;p&gt;This one is uncontroversial. If you have a genuinely heavy calculation — sorting a large array, filtering thousands of rows, running some numeric computation — recomputing it on every render (including renders triggered by unrelated state) is wasteful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filters&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;matchesFilters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;useMemo&lt;/code&gt;, every re-render of &lt;code&gt;ProductList&lt;/code&gt; — even one triggered by, say, a tooltip's hover state — would re-run the filter over the whole array. With it, the filter only reruns when &lt;code&gt;products&lt;/code&gt; or &lt;code&gt;filters&lt;/code&gt; actually change.&lt;/p&gt;

&lt;p&gt;The key word is &lt;em&gt;expensive&lt;/em&gt;. Filtering 20 items is not expensive. Filtering 20,000 items, or running a computation with real algorithmic weight, is. Don't reach for &lt;code&gt;useMemo&lt;/code&gt; reflexively — profile first, or at least reason about the actual cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  The case that trips people up: referential stability
&lt;/h2&gt;

&lt;p&gt;This is where most of the confusion lives. &lt;code&gt;useCallback&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt; matter for referential stability in two situations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. When a value or function is a dependency of another hook.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchBox&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSearch&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// if onSearch changes identity every render, this debounce is recreated every time&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;onSearch&lt;/code&gt; isn't stable, &lt;code&gt;useEffect&lt;/code&gt;, &lt;code&gt;useMemo&lt;/code&gt;, or a custom hook relying on it as a dependency will re-run constantly, potentially defeating the entire purpose of the debounce, subscription, or cache it's feeding into.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. When a value is passed to a memoized child component.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ExpensiveChild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ExpensiveChild&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// heavy render logic&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

  &lt;span class="c1"&gt;// Without useCallback, this is a NEW function every render,&lt;/span&gt;
  &lt;span class="c1"&gt;// which defeats React.memo on ExpensiveChild entirely.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ExpensiveChild&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;React.memo&lt;/code&gt; on &lt;code&gt;ExpensiveChild&lt;/code&gt; only pays off if the props it receives are stable. If &lt;code&gt;handleClick&lt;/code&gt; is a new reference on every render, &lt;code&gt;React.memo&lt;/code&gt; does nothing — the child re-renders anyway, and you've added the overhead of &lt;code&gt;React.memo&lt;/code&gt;'s comparison for no benefit.&lt;/p&gt;

&lt;p&gt;This is the important part: &lt;strong&gt;&lt;code&gt;useCallback&lt;/code&gt; without &lt;code&gt;React.memo&lt;/code&gt; (or a dependency array somewhere downstream) usually does nothing useful.&lt;/strong&gt; The two are a pair. If nothing consumes the stable reference, you're just adding bookkeeping.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it's &lt;em&gt;not&lt;/em&gt; worth it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple values or inline functions passed to plain DOM elements.&lt;/strong&gt; &lt;code&gt;&amp;lt;button onClick={() =&amp;gt; setOpen(true)}&amp;gt;&lt;/code&gt; does not need &lt;code&gt;useCallback&lt;/code&gt;. DOM elements aren't memoized components; a new function reference every render costs essentially nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheap computations.&lt;/strong&gt; &lt;code&gt;const total = a + b&lt;/code&gt; doesn't need &lt;code&gt;useMemo&lt;/code&gt;. The comparison overhead of the hook can genuinely exceed the cost of just recalculating.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Just in case" usage without a memoized consumer.&lt;/strong&gt; If nothing downstream is &lt;code&gt;React.memo&lt;/code&gt;-wrapped and nothing uses the value as a dependency, the memoization has no one to benefit from it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Values that change on every render anyway.&lt;/strong&gt; If a dependency changes every render, &lt;code&gt;useMemo&lt;/code&gt; will recompute every time too — you get the comparison cost &lt;em&gt;and&lt;/em&gt; the recomputation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A practical mental checklist
&lt;/h2&gt;

&lt;p&gt;Before adding &lt;code&gt;useMemo&lt;/code&gt; or &lt;code&gt;useCallback&lt;/code&gt;, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is this computation actually expensive&lt;/strong&gt;, or does it just look intimidating? (Measure if unsure.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does something downstream depend on referential equality&lt;/strong&gt; — a &lt;code&gt;React.memo&lt;/code&gt; child, a &lt;code&gt;useEffect&lt;/code&gt; dependency, a custom hook's cache key?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do the dependencies change rarely&lt;/strong&gt; relative to how often the component re-renders? If they change every time anyway, memoization buys nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the answer to #1 or #2 is no, you probably don't need the hook.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on the React Compiler
&lt;/h2&gt;

&lt;p&gt;It's worth mentioning: the React team has been building an automatic compiler (React Compiler, formerly "React Forget") specifically to memoize things like this automatically, precisely because manual &lt;code&gt;useMemo&lt;/code&gt;/&lt;code&gt;useCallback&lt;/code&gt; placement is easy to get wrong and tedious to maintain. That's a strong signal about how the React team itself views manual memoization — as a mechanism you should reach for deliberately, not a reflex.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt; are not performance switches you flip on by default. They're targeted tools for two specific problems: avoiding expensive recomputation, and preserving referential stability for something that actually checks for it. Used with intent, they meaningfully help. Used everywhere, they add cognitive overhead and runtime cost while often fixing nothing at all.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Where to get cover images for a post like this: for genuinely free-to-use, no-attribution-needed photos, &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt; and &lt;a href="https://pexels.com" rel="noopener noreferrer"&gt;Pexels&lt;/a&gt; are the standard choices for dev.to-style covers — search something like "code" or "abstract programming." For a more on-topic illustration (e.g. a diagram-style cover), you can also generate a simple custom SVG/graphic yourself — dev.to covers are just images, so anything royalty-free works.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How I Used BFS to Find the Shortest Route in Tehran Metro with React</title>
      <dc:creator>Hamed Farazi</dc:creator>
      <pubDate>Mon, 10 Aug 2026 22:48:07 +0000</pubDate>
      <link>https://dev.to/hamedfarazi/how-i-used-bfs-to-find-the-shortest-route-in-tehran-metro-with-react-3p8o</link>
      <guid>https://dev.to/hamedfarazi/how-i-used-bfs-to-find-the-shortest-route-in-tehran-metro-with-react-3p8o</guid>
      <description>&lt;p&gt;When I started building Metrino, a Tehran Metro route planner, I had a simple question:&lt;/p&gt;

&lt;p&gt;«How can I find the shortest route between two metro stations?»&lt;/p&gt;

&lt;p&gt;The UI was only one part of the problem. Underneath the map and station selectors, I needed a way to represent the Tehran Metro network and calculate a route between two stations.&lt;/p&gt;

&lt;p&gt;The solution was to model the metro network as a graph and use Breadth-First Search (BFS) to find the shortest path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpblp19cwql7hhc8nsbqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpblp19cwql7hhc8nsbqx.png" alt=" " width="800" height="723"&gt;&lt;/a&gt;&lt;br&gt;
🚇 Turning the Metro Into a Graph&lt;/p&gt;

&lt;p&gt;Instead of thinking about the metro as a visual map, I represented it as a graph.&lt;/p&gt;

&lt;p&gt;Each station is a node.&lt;/p&gt;

&lt;p&gt;Each connection between two stations is an edge.&lt;/p&gt;

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

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Station A&lt;br&gt;
    │&lt;br&gt;
    ▼&lt;br&gt;
Station B ─── Station C&lt;br&gt;
                 │&lt;br&gt;
                 ▼&lt;br&gt;
              Station D&lt;/p&gt;

&lt;p&gt;In my data model, each station contains a list of connected stations.&lt;/p&gt;

&lt;p&gt;This means I can ask:&lt;/p&gt;

&lt;p&gt;«"Which stations can I reach directly from this station?"»&lt;/p&gt;

&lt;p&gt;The application builds a bidirectional adjacency map when the metro data is initialized:&lt;/p&gt;

&lt;p&gt;const adj = new Map&amp;gt;();&lt;/p&gt;

&lt;p&gt;this._stations.forEach((s) =&amp;gt; {&lt;br&gt;
  if (!adj.has(s.id)) adj.set(s.id, new Set());&lt;/p&gt;

&lt;p&gt;s.connectedStationIds.forEach((nid) =&amp;gt; {&lt;br&gt;
    adj.get(s.id)!.add(nid);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Add reverse direction
if (!adj.has(nid)) adj.set(nid, new Set());
adj.get(nid)!.add(s.id);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;This gives the route finder a structure that is easy to traverse.&lt;/p&gt;

&lt;p&gt;🧭 Why BFS?&lt;/p&gt;

&lt;p&gt;For the first version of the route planner, I wanted to minimize the number of station-to-station hops.&lt;/p&gt;

&lt;p&gt;That's where BFS works well.&lt;/p&gt;

&lt;p&gt;Breadth-First Search explores a graph level by level:&lt;/p&gt;

&lt;p&gt;Start&lt;br&gt;
 │&lt;br&gt;
 ├── A&lt;br&gt;
 ├── B&lt;br&gt;
 └── C&lt;br&gt;
      │&lt;br&gt;
      ├── D&lt;br&gt;
      ├── E&lt;br&gt;
      └── F&lt;/p&gt;

&lt;p&gt;It first explores the stations closest to the starting station, then moves to the next level.&lt;/p&gt;

&lt;p&gt;Because every connection has the same cost in this version of the problem, the first route BFS finds to the destination is the route with the fewest hops.&lt;/p&gt;

&lt;p&gt;💻 The Actual BFS Implementation&lt;/p&gt;

&lt;p&gt;Here is the actual "findPath" implementation from Metrino:&lt;/p&gt;

&lt;p&gt;findPath(fromId: string, toId: string): string[] | null {&lt;br&gt;
  if (fromId === toId) return [fromId];&lt;/p&gt;

&lt;p&gt;const visited = new Set();&lt;/p&gt;

&lt;p&gt;const queue: Array&amp;lt;{ id: string; path: string[] }&amp;gt; = [&lt;br&gt;
    { id: fromId, path: [fromId] },&lt;br&gt;
  ];&lt;/p&gt;

&lt;p&gt;visited.add(fromId);&lt;/p&gt;

&lt;p&gt;while (queue.length &amp;gt; 0) {&lt;br&gt;
    const { id, path } = queue.shift()!;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const neighbors = this._adjacency.get(id) ?? [];

for (const neighbor of neighbors) {
  if (neighbor === toId) {
    return [...path, neighbor];
  }

  if (!visited.has(neighbor)) {
    visited.add(neighbor);

    queue.push({
      id: neighbor,
      path: [...path, neighbor],
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;return null;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Let's break it down.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handle the same station&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;if (fromId === toId) return [fromId];&lt;/p&gt;

&lt;p&gt;If the origin and destination are the same station, there is nothing to calculate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep track of visited stations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;const visited = new Set();&lt;/p&gt;

&lt;p&gt;Without this, the algorithm could keep visiting the same stations again and again.&lt;/p&gt;

&lt;p&gt;I immediately mark the starting station as visited:&lt;/p&gt;

&lt;p&gt;visited.add(fromId);&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the queue&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;const queue: Array&amp;lt;{ id: string; path: string[] }&amp;gt; = [&lt;br&gt;
  { id: fromId, path: [fromId] },&lt;br&gt;
];&lt;/p&gt;

&lt;p&gt;The queue contains the station we're currently exploring and the path that led to it.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  id: "station-b",&lt;br&gt;
  path: ["station-a", "station-b"]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This makes it easy to return the complete route once we reach the destination.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explore the graph&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;while (queue.length &amp;gt; 0) {&lt;/p&gt;

&lt;p&gt;As long as there are stations waiting to be explored, BFS continues.&lt;/p&gt;

&lt;p&gt;We remove the first item from the queue:&lt;/p&gt;

&lt;p&gt;const { id, path } = queue.shift()!;&lt;/p&gt;

&lt;p&gt;Then get all directly connected stations:&lt;/p&gt;

&lt;p&gt;const neighbors = this._adjacency.get(id) ?? [];&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the destination&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;if (neighbor === toId) {&lt;br&gt;
  return [...path, neighbor];&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;As soon as BFS reaches the destination, we return the complete station sequence.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Station A&lt;br&gt;
   ↓&lt;br&gt;
Station B&lt;br&gt;
   ↓&lt;br&gt;
Station C&lt;br&gt;
   ↓&lt;br&gt;
Station D&lt;/p&gt;

&lt;p&gt;The returned result would look like:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
  "station-a",&lt;br&gt;
  "station-b",&lt;br&gt;
  "station-c",&lt;br&gt;
  "station-d"&lt;br&gt;
]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add unvisited stations to the queue&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;if (!visited.has(neighbor)) {&lt;br&gt;
  visited.add(neighbor);&lt;/p&gt;

&lt;p&gt;queue.push({&lt;br&gt;
    id: neighbor,&lt;br&gt;
    path: [...path, neighbor],&lt;br&gt;
  });&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is what allows BFS to move through the network level by level.&lt;/p&gt;

&lt;p&gt;🔄 What About Line Transfers?&lt;/p&gt;

&lt;p&gt;Finding the shortest path is only part of the problem.&lt;/p&gt;

&lt;p&gt;Tehran Metro has multiple lines, so after finding the station path, I also need to determine where passengers change lines.&lt;/p&gt;

&lt;p&gt;The route service looks at consecutive stations and finds their shared line:&lt;/p&gt;

&lt;p&gt;private _getCommonLine(a: Station, b: Station): number | null {&lt;br&gt;
  for (const line of a.lines) {&lt;br&gt;
    if (b.lines.includes(line)) return line;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;return null;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Then the route builder can detect when the route changes from one line to another.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Line 1&lt;br&gt;
  │&lt;br&gt;
  │&lt;br&gt;
  ▼&lt;br&gt;
Station A&lt;br&gt;
  │&lt;br&gt;
  ▼&lt;br&gt;
Transfer Station&lt;br&gt;
  │&lt;br&gt;
  │&lt;br&gt;
  ▼&lt;br&gt;
Line 4&lt;br&gt;
  │&lt;br&gt;
  ▼&lt;br&gt;
Station B&lt;/p&gt;

&lt;p&gt;The transfer is recorded separately from the BFS path.&lt;/p&gt;

&lt;p&gt;⏱️ Estimating Travel Time&lt;/p&gt;

&lt;p&gt;BFS gives me the route, but it doesn't tell me how long the journey will take.&lt;/p&gt;

&lt;p&gt;So after finding the path, Metrino calculates an estimated travel time using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;approximate distance between stations&lt;/li&gt;
&lt;li&gt;an average train speed&lt;/li&gt;
&lt;li&gt;station dwell time&lt;/li&gt;
&lt;li&gt;transfer time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current implementation uses:&lt;/p&gt;

&lt;p&gt;const TRANSFER_PENALTY_MIN = 3;&lt;br&gt;
const STATION_DWELL_SEC = 30;&lt;br&gt;
const AVG_SPEED_KMH = 40;&lt;/p&gt;

&lt;p&gt;The total estimate is then built from these values.&lt;/p&gt;

&lt;p&gt;These are estimates, not official Tehran Metro schedules.&lt;/p&gt;

&lt;p&gt;🧩 Separating the Algorithm From the UI&lt;/p&gt;

&lt;p&gt;One thing I wanted to avoid was putting route calculation directly inside React components.&lt;/p&gt;

&lt;p&gt;Instead, I separated the responsibilities:&lt;/p&gt;

&lt;p&gt;React UI&lt;br&gt;
   ↓&lt;br&gt;
MetroRouteService&lt;br&gt;
   ↓&lt;br&gt;
MetroDataService&lt;br&gt;
   ↓&lt;br&gt;
Metro Graph / Metro Data&lt;/p&gt;

&lt;p&gt;"MetroDataService" handles the station, line, connection, and adjacency data.&lt;/p&gt;

&lt;p&gt;"MetroRouteService" takes the resulting path and turns it into a complete route containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;origin&lt;/li&gt;
&lt;li&gt;destination&lt;/li&gt;
&lt;li&gt;station sequence&lt;/li&gt;
&lt;li&gt;segments&lt;/li&gt;
&lt;li&gt;transfers&lt;/li&gt;
&lt;li&gt;distance&lt;/li&gt;
&lt;li&gt;estimated time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation makes the UI much easier to work with.&lt;/p&gt;

&lt;p&gt;📈 What's Next?&lt;/p&gt;

&lt;p&gt;BFS was a good starting point because the first version of Metrino only needed to minimize the number of station hops.&lt;/p&gt;

&lt;p&gt;But the real-world "best route" isn't always the route with the fewest stations.&lt;/p&gt;

&lt;p&gt;For example, a slightly longer route might be better if it has fewer transfers or takes less time.&lt;/p&gt;

&lt;p&gt;That's why one of the next improvements I'd like to explore is weighted pathfinding, using algorithms such as Dijkstra's algorithm or A*.&lt;/p&gt;

&lt;p&gt;The goal would be to consider things like:&lt;/p&gt;

&lt;p&gt;Station count&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Travel time&lt;/li&gt;
&lt;li&gt;Transfer penalties&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;instead of only counting station hops.&lt;/p&gt;

&lt;p&gt;🚀 What I Learned&lt;/p&gt;

&lt;p&gt;The biggest lesson from building this feature was that many problems that look like UI problems are actually data structure and algorithm problems.&lt;/p&gt;

&lt;p&gt;The metro map is a UI.&lt;/p&gt;

&lt;p&gt;But underneath that UI, it's a graph.&lt;/p&gt;

&lt;p&gt;Once I represented the metro network as a graph, route calculation became much easier to reason about.&lt;/p&gt;

&lt;p&gt;BFS gave me a simple and reliable starting point, and it was enough to power the first version of the route planner.&lt;/p&gt;

&lt;p&gt;🚇 Try Metrino&lt;/p&gt;

&lt;p&gt;I built Metrino as a Persian-first Tehran Metro web application with React, TypeScript and Vite.&lt;/p&gt;

&lt;p&gt;Live Demo: &lt;a href="https://metrino.vercel.app/" rel="noopener noreferrer"&gt;https://metrino.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/HamedFarazi/metroapp" rel="noopener noreferrer"&gt;https://github.com/HamedFarazi/metroapp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is open source, and I'm continuing to improve the routing, maps, PWA experience, and accessibility.&lt;/p&gt;

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

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
