<?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: hardik kuwar</title>
    <description>The latest articles on DEV Community by hardik kuwar (@hardik_kuwar_7caa4626bb16).</description>
    <link>https://dev.to/hardik_kuwar_7caa4626bb16</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%2F1917447%2F818307e5-b597-4a81-a8b4-70472e67bc85.png</url>
      <title>DEV Community: hardik kuwar</title>
      <link>https://dev.to/hardik_kuwar_7caa4626bb16</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hardik_kuwar_7caa4626bb16"/>
    <language>en</language>
    <item>
      <title>Hearth: I turned my habits into literal fires that die if I ignore them</title>
      <dc:creator>hardik kuwar</dc:creator>
      <pubDate>Sun, 12 Jul 2026 14:48:33 +0000</pubDate>
      <link>https://dev.to/hardik_kuwar_7caa4626bb16/hearth-i-turned-my-habits-into-literal-fires-that-die-if-i-ignore-them-2p1i</link>
      <guid>https://dev.to/hardik_kuwar_7caa4626bb16/hearth-i-turned-my-habits-into-literal-fires-that-die-if-i-ignore-them-2p1i</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Hearth is a campfire for the things you care about.&lt;/p&gt;

&lt;p&gt;Every passion you're tending (the gym, a book, a side project, a skill you keep meaning to learn) is a literal fire on screen. Spend time on it and log the minutes ("add a spark"), and the flame grows. Ignore it and it slowly sinks down to embers. It never fully dies though, which felt important. Real passions don't either. One spark and it's back.&lt;/p&gt;

&lt;p&gt;The idea came from the &lt;strong&gt;Olympic flame&lt;/strong&gt;. They light the cauldron at the opening ceremony and it burns for the whole games, and every win along the way feels like it's feeding that one fire. I wanted that for ordinary life: my gym sessions and reading nights as small victories thrown into a flame that's mine. Every habit tracker I've tried does the opposite. It guilt-trips me with grey squares and broken streaks. So instead of a grid, you get a night scene with your fires burning along the ground, and a big central flame (labelled "You") that every one of them feeds, like a personal cauldron.&lt;/p&gt;

&lt;p&gt;A few things it does:&lt;/p&gt;

&lt;p&gt;Warmth decays on a half-life, in real time. A daily habit cools in about 3.5 days, but a monthly one (like "learn a new skill") stays warm for weeks, because punishing a monthly goal on a daily clock is just mean.&lt;br&gt;
Streaks understand cadence too. Gym counts consecutive days, "build a product" counts consecutive weeks, so a weekly flame doesn't show a permanent streak of zero.&lt;br&gt;
Optional fire crackle sound, and the volume actually follows how warm your hearth is. A dying hearth gets quiet.&lt;br&gt;
Respects prefers-reduced-motion with a calm, still render instead of the particle animation.&lt;br&gt;
Everything lives in localStorage. No accounts, no server, nobody's dashboard.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://hardboyyy.github.io/hearth-fire/" rel="noopener noreferrer"&gt;https://hardboyyy.github.io/hearth-fire/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quick tour: open it, and the left panel explains the metaphor. Five starter fires are already laid out (gym, reading, coding practice, building a product, learning a new skill). Click one, log 30 minutes, and watch it flare up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/hardboyyy/hearth-fire" rel="noopener noreferrer"&gt;https://github.com/hardboyyy/hearth-fire&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How I Built It&lt;br&gt;
Three files: index.html, style.css, script.js. No framework, no build step, no dependencies. You open the HTML file and it runs.&lt;/p&gt;

&lt;p&gt;The fire is a little particle system on a canvas. Each flame keeps spawning glowing dots that rise, drift in a fake wind, and fade out. The more you've tended a fire, the more and bigger the particles, so a healthy fire literally burns taller.&lt;/p&gt;

&lt;p&gt;The math is one idea: every logged session is a spark worth its minutes, and that value halves on a schedule (every 3.5 days for daily habits, slower for weekly and monthly ones). Add up the sparks and you get the fire's warmth. Fires cool on their own, old effort never quite reaches zero, and a single fresh spark visibly revives a dying flame.&lt;/p&gt;

&lt;p&gt;Streaks work by turning dates into simple numbers (day number, week number, month number) and checking they run consecutively. That's how one loop handles daily, weekly and monthly habits.&lt;/p&gt;

&lt;p&gt;A few console.assert checks run on every page load to make sure the decay and streak math still behaves. Not a test suite, but it's caught me twice already.&lt;/p&gt;

&lt;p&gt;With another weekend I'd add editing a fire's cadence and maybe a gentle "this fire is getting cold" nudge. But the whole point is that the app doesn't nag you. The fire just gets smaller, and somehow that's more motivating than any notification.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>𝗠𝗼𝘀𝘁 𝗖𝗦𝗦 𝘀𝗽𝗮𝗰𝗶𝗻𝗴 𝗯𝘂𝗴𝘀 𝘀𝘁𝗮𝗿𝘁 𝘄𝗶𝘁𝗵 𝗼𝗻𝗲 𝗯𝗮𝘀𝗶𝗰 𝗰𝗼𝗻𝗳𝘂𝘀𝗶𝗼𝗻: 𝗽𝗮𝗱𝗱𝗶𝗻𝗴 𝘃𝘀 𝗺𝗮𝗿𝗴𝗶𝗻.</title>
      <dc:creator>hardik kuwar</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:50:41 +0000</pubDate>
      <link>https://dev.to/hardik_kuwar_7caa4626bb16/--1k2h</link>
      <guid>https://dev.to/hardik_kuwar_7caa4626bb16/--1k2h</guid>
      <description>&lt;p&gt;At first, both seem to do the same thing —&lt;br&gt;
they both create space.&lt;/p&gt;

&lt;p&gt;So it’s easy to assume you can use either one.&lt;/p&gt;

&lt;p&gt;But that’s exactly where layout bugs start.&lt;/p&gt;

&lt;p&gt;Because if you don’t understand where the space is being added, your UI starts behaving in weird ways.&lt;/p&gt;

&lt;p&gt;𝗧𝗵𝗲 𝘀𝗶𝗺𝗽𝗹𝗲𝘀𝘁 𝘄𝗮𝘆 𝘁𝗼 𝘁𝗵𝗶𝗻𝗸 𝗮𝗯𝗼𝘂𝘁 𝗶𝘁 👇&lt;/p&gt;

&lt;p&gt;• Padding → adds space inside the element&lt;br&gt;
• Margin → adds space outside the element&lt;/p&gt;

&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;But that one distinction solves a surprising number of frontend bugs.&lt;/p&gt;

&lt;p&gt;𝗤𝘂𝗶𝗰𝗸 𝗲𝘅𝗮𝗺𝗽𝗹𝗲&lt;/p&gt;

&lt;p&gt;Imagine you have a card with a button inside it.&lt;/p&gt;

&lt;p&gt;If the text inside the button feels too close to the edges,&lt;br&gt;
you need padding.&lt;/p&gt;

&lt;p&gt;If the button itself is too close to the next section or the card below it,&lt;br&gt;
you need margin.&lt;/p&gt;

&lt;p&gt;𝗧𝗵𝗲 𝗿𝘂𝗹𝗲 𝗜 𝘂𝘀𝘂𝗮𝗹𝗹𝘆 𝗳𝗼𝗹𝗹𝗼𝘄&lt;/p&gt;

&lt;p&gt;• If the content inside an element feels too tight → use padding&lt;br&gt;
• If two elements are too close to each other → use margin&lt;/p&gt;

&lt;p&gt;Simple rule.&lt;br&gt;
But it clears up a lot of CSS confusion.&lt;/p&gt;

&lt;p&gt;𝗪𝗵𝘆 𝘁𝗵𝗶𝘀 𝗺𝗮𝘁𝘁𝗲𝗿𝘀&lt;/p&gt;

&lt;p&gt;A lot of CSS bugs are not actually “hard CSS problems”.&lt;/p&gt;

&lt;p&gt;They come from misunderstanding inside spacing vs outside spacing.&lt;/p&gt;

&lt;p&gt;And once you get this right, your layouts become much easier to reason about.&lt;/p&gt;

&lt;p&gt;What CSS concept confused you the most when you started frontend?&lt;/p&gt;

</description>
      <category>css</category>
      <category>tailwindcss</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>One of the Most Expensive Engineering Mistakes? Letting Dependency Updates Pile Up</title>
      <dc:creator>hardik kuwar</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:11:00 +0000</pubDate>
      <link>https://dev.to/hardik_kuwar_7caa4626bb16/one-of-the-most-expensive-engineering-mistakes-letting-dependency-updates-pile-up-33mc</link>
      <guid>https://dev.to/hardik_kuwar_7caa4626bb16/one-of-the-most-expensive-engineering-mistakes-letting-dependency-updates-pile-up-33mc</guid>
      <description>&lt;p&gt;Most dependency debt doesn’t start with negligence.&lt;/p&gt;

&lt;p&gt;It starts with a project that feels stable.&lt;/p&gt;

&lt;p&gt;The app is working, the team is shipping features, and nobody wants to risk touching packages that “already work.” So dependency updates get postponed. Not forever — just until there’s more time.&lt;/p&gt;

&lt;p&gt;Then one day someone tries to update a package that’s two or three years behind.&lt;/p&gt;

&lt;p&gt;And what should have been a small maintenance task turns into a mini migration project.&lt;/p&gt;

&lt;p&gt;One upgrade breaks another.&lt;br&gt;
Peer dependency conflicts start appearing.&lt;br&gt;
Deprecated APIs stop working.&lt;br&gt;
Build issues start eating hours that should have gone into shipping features.&lt;/p&gt;

&lt;p&gt;At that point, the problem is no longer “we need to update a dependency.”&lt;/p&gt;

&lt;p&gt;The problem is that the team has let &lt;strong&gt;dependency debt&lt;/strong&gt; build up long enough that a routine upgrade is no longer routine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why delayed dependency updates get expensive
&lt;/h2&gt;

&lt;p&gt;The cost of delaying updates is rarely visible in the moment.&lt;/p&gt;

&lt;p&gt;That’s why teams keep doing it.&lt;/p&gt;

&lt;p&gt;Nothing looks broken. The product still works. Customers don’t care that a UI library or test runner is behind by a few versions. So upgrades get pushed below feature work, bug fixes, and deadlines.&lt;/p&gt;

&lt;p&gt;The trouble starts later, when the team finally has a reason to update.&lt;/p&gt;

&lt;p&gt;By then, the ecosystem around the project has already moved on.&lt;/p&gt;

&lt;p&gt;And that’s the key issue: &lt;strong&gt;dependencies don’t evolve in isolation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In frontend projects especially, package ecosystems are tightly connected.&lt;/p&gt;

&lt;p&gt;A framework upgrade may affect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your UI library&lt;/li&gt;
&lt;li&gt;testing setup&lt;/li&gt;
&lt;li&gt;linting plugins&lt;/li&gt;
&lt;li&gt;build tooling&lt;/li&gt;
&lt;li&gt;TypeScript compatibility&lt;/li&gt;
&lt;li&gt;internal wrappers built around older APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when a project is years behind, you’re rarely updating one package. You’re stepping into a chain of upgrades.&lt;/p&gt;

&lt;h2&gt;
  
  
  A realistic example of how this happens
&lt;/h2&gt;

&lt;p&gt;Imagine a frontend team working on a SaaS product.&lt;/p&gt;

&lt;p&gt;The app has been stable for a while, so dependency updates keep getting pushed. There’s always something more urgent: a launch, a bug fix, a customer request, a redesign.&lt;/p&gt;

&lt;p&gt;For two years, the team delays most major dependency work.&lt;/p&gt;

&lt;p&gt;Then they decide to upgrade one important package — maybe React, maybe a framework dependency, maybe a UI library they need to modernize.&lt;/p&gt;

&lt;p&gt;The expectation is simple: update the package, fix a few things, move on.&lt;/p&gt;

&lt;p&gt;Instead, the upgrade starts pulling other work with it.&lt;/p&gt;

&lt;p&gt;The newer React version forces changes in the testing setup.&lt;br&gt;
The UI library has breaking API changes.&lt;br&gt;
Some ESLint plugins no longer support the old configuration.&lt;br&gt;
A few internal components were built around deprecated behavior and now need refactoring.&lt;br&gt;
Build tooling starts surfacing compatibility issues that were hidden before.&lt;/p&gt;

&lt;p&gt;What looked like a small update becomes weeks of cleanup, retesting, and cautious releases.&lt;/p&gt;

&lt;p&gt;Nothing catastrophic happened. The team didn’t make a terrible engineering decision.&lt;/p&gt;

&lt;p&gt;They just let routine maintenance drift long enough that the cost came due all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is why “we’ll update it later” becomes expensive
&lt;/h2&gt;

&lt;p&gt;The real problem with dependency debt isn’t just outdated packages. It’s &lt;strong&gt;upgrade shock&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Small, regular updates usually mean you’re dealing with a smaller set of changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer breaking changes&lt;/li&gt;
&lt;li&gt;fewer compatibility issues&lt;/li&gt;
&lt;li&gt;less code to refactor at once&lt;/li&gt;
&lt;li&gt;lower release risk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Delayed upgrades do the opposite.&lt;/p&gt;

&lt;p&gt;Now you’re crossing multiple release cycles in one shot. You’re dealing with several rounds of breaking changes, deprecated APIs, tooling shifts, and migration requirements all at once.&lt;/p&gt;

&lt;p&gt;A normal maintenance task turns into a project.&lt;/p&gt;

&lt;p&gt;That’s why delayed upgrades feel so expensive: not because updating is bad, but because &lt;strong&gt;you compressed too much change into one event.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That doesn’t mean you should update everything constantly
&lt;/h2&gt;

&lt;p&gt;This is where the conversation usually gets oversimplified.&lt;/p&gt;

&lt;p&gt;I’m not saying teams should blindly update every dependency every week. That creates a different kind of noise.&lt;/p&gt;

&lt;p&gt;Updates still need time, testing, and judgment. Some packages matter far more than others. And sometimes a major version bump genuinely deserves planning instead of being merged casually.&lt;/p&gt;

&lt;p&gt;The goal isn’t “always be on the latest version.”&lt;/p&gt;

&lt;p&gt;The goal is to avoid letting dependency maintenance become a once-a-year rescue mission.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical team approach that works better
&lt;/h2&gt;

&lt;p&gt;What has worked much better for teams in the long run is a simple rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;treat dependency maintenance as recurring engineering work, not cleanup work.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That usually means a few things.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Watch the dependencies that can create real upgrade pain
&lt;/h3&gt;

&lt;p&gt;Not every package needs the same attention.&lt;/p&gt;

&lt;p&gt;Focus more on dependencies that are deeply tied to the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;framework dependencies&lt;/li&gt;
&lt;li&gt;UI libraries&lt;/li&gt;
&lt;li&gt;build tooling&lt;/li&gt;
&lt;li&gt;test tooling&lt;/li&gt;
&lt;li&gt;TypeScript / linting ecosystem&lt;/li&gt;
&lt;li&gt;data/state libraries that are widely used across the codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the packages most likely to create upgrade debt if ignored for too long.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Prefer small regular updates over rare catch-up upgrades
&lt;/h3&gt;

&lt;p&gt;A lightweight monthly or quarterly dependency review is usually far safer than waiting until the project is years behind.&lt;/p&gt;

&lt;p&gt;Not because every update is urgent.&lt;/p&gt;

&lt;p&gt;But because smaller upgrade windows keep the surface area of change manageable.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Budget a little maintenance time before it becomes emergency work
&lt;/h3&gt;

&lt;p&gt;If dependency work only happens “when there’s time,” it usually won’t happen until there’s pain.&lt;/p&gt;

&lt;p&gt;Teams don’t need a huge maintenance program for this. They just need enough recurring space that upgrades don’t get ignored indefinitely.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Don’t batch everything into one giant modernization effort unless you have to
&lt;/h3&gt;

&lt;p&gt;When multiple major upgrades move together, testing gets harder, rollback gets harder, and the blast radius gets bigger.&lt;/p&gt;

&lt;p&gt;If you can keep upgrades more isolated, you keep control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real value of staying reasonably up to date
&lt;/h2&gt;

&lt;p&gt;Yes, you get the obvious benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;newer features&lt;/li&gt;
&lt;li&gt;performance improvements&lt;/li&gt;
&lt;li&gt;security fixes&lt;/li&gt;
&lt;li&gt;better docs and ecosystem support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the bigger benefit is flexibility.&lt;/p&gt;

&lt;p&gt;A codebase that stays reasonably current is easier to evolve when product priorities change. You’re not forced into a painful dependency catch-up project every time you want to adopt a newer tool, upgrade your framework, or modernize a part of the stack.&lt;/p&gt;

&lt;p&gt;You preserve momentum.&lt;/p&gt;

&lt;p&gt;And in long-lived products, that matters a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Small dependency updates feel annoying because the app already works and there’s always something more urgent to do.&lt;/p&gt;

&lt;p&gt;But when those updates keep getting postponed, the cost doesn’t disappear. It compounds.&lt;/p&gt;

&lt;p&gt;And eventually, a routine version bump turns into a migration project that steals time from the roadmap.&lt;/p&gt;

&lt;p&gt;So no — I’m not arguing for constant dependency churn.&lt;/p&gt;

&lt;p&gt;I’m arguing against waiting so long that a normal upgrade becomes a painful one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small regular updates feel annoying.&lt;br&gt;
Big delayed upgrades feel brutal.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>software</category>
      <category>productivity</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The mistake is assuming data shape and state shape should always match</title>
      <dc:creator>hardik kuwar</dc:creator>
      <pubDate>Mon, 22 Jun 2026 16:32:07 +0000</pubDate>
      <link>https://dev.to/hardik_kuwar_7caa4626bb16/the-mistake-is-assuming-data-shape-and-state-shape-should-always-match-5g0e</link>
      <guid>https://dev.to/hardik_kuwar_7caa4626bb16/the-mistake-is-assuming-data-shape-and-state-shape-should-always-match-5g0e</guid>
      <description>&lt;p&gt;When you first build a form in React, putting everything into one big state object feels like the cleanest option.&lt;/p&gt;

&lt;p&gt;It mirrors the UI nicely.&lt;br&gt;
Personal info goes under &lt;code&gt;personalInfo&lt;/code&gt;.&lt;br&gt;
Address fields go under &lt;code&gt;address&lt;/code&gt;.&lt;br&gt;
Education, projects, company details — each section gets its own nested object.&lt;/p&gt;

&lt;p&gt;At that stage, it feels organized. Maybe even “well structured.”&lt;/p&gt;

&lt;p&gt;Then you try to update a single field.&lt;/p&gt;

&lt;p&gt;Not the whole form. Not even a section. Just one field — say &lt;code&gt;city&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And suddenly a simple update doesn’t feel simple anymore.&lt;/p&gt;

&lt;p&gt;To change that one value, you often have to recreate the top-level form object, then the nested address object, and only then the &lt;code&gt;city&lt;/code&gt; field itself. What should have been a tiny change starts feeling oddly heavy.&lt;/p&gt;

&lt;p&gt;That’s the point where many React forms begin to feel harder to maintain than they should.&lt;/p&gt;

&lt;p&gt;And usually, the problem isn’t React. It’s the shape of the state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this happens so often
&lt;/h2&gt;

&lt;p&gt;Nested form state usually comes from a reasonable instinct.&lt;/p&gt;

&lt;p&gt;If the form has clear sections, it feels natural to model the state the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;personal information&lt;/li&gt;
&lt;li&gt;address&lt;/li&gt;
&lt;li&gt;company details&lt;/li&gt;
&lt;li&gt;education&lt;/li&gt;
&lt;li&gt;projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a data modeling perspective, that looks neat. Related fields stay grouped together. The state object resembles the structure of the form on the screen. If you log it in the console, it looks clean and easy to understand.&lt;/p&gt;

&lt;p&gt;The issue is that forms are not static data structures. They are interactive systems.&lt;/p&gt;

&lt;p&gt;Users don’t update forms section by section. They update them field by field.&lt;/p&gt;

&lt;p&gt;They type into one input.&lt;br&gt;
They clear one dropdown.&lt;br&gt;
They add one entry to a repeatable section.&lt;br&gt;
They toggle one checkbox that changes another part of the form.&lt;/p&gt;

&lt;p&gt;So the real question isn’t just &lt;em&gt;“Does this state look organized?”&lt;/em&gt;&lt;br&gt;
It’s &lt;em&gt;“Does this state make small, frequent updates easy?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s where deeply nested form state starts working against you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem is bigger than verbose update code
&lt;/h2&gt;

&lt;p&gt;The first pain point is obvious: nested state makes updates more annoying.&lt;/p&gt;

&lt;p&gt;A small change often means copying multiple layers of objects just to preserve immutability. That alone is enough to make a form feel clunky to work on.&lt;/p&gt;

&lt;p&gt;But the bigger problem is what comes after that.&lt;/p&gt;

&lt;p&gt;As the form grows, nested state doesn’t just make updates verbose. It makes the entire feature harder to evolve. The complexity starts leaking into validation, rendering, component boundaries, and day-to-day maintenance.&lt;/p&gt;

&lt;p&gt;In practice, it usually shows up in three ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Small changes start touching more state than they should
&lt;/h2&gt;

&lt;p&gt;A user updates one field, but the code has to recreate multiple layers of the object tree to make that happen safely.&lt;/p&gt;

&lt;p&gt;Technically, that’s expected. React state updates are immutable, so changing a deeply nested value means recreating every object on the path to that value.&lt;/p&gt;

&lt;p&gt;The problem is not that React requires this. The problem is what it does to the developer experience once the form stops being small.&lt;/p&gt;

&lt;p&gt;A simple update no longer feels local. It feels structural.&lt;/p&gt;

&lt;p&gt;Instead of focusing on the actual behavior — updating a city, changing a salary, editing a project title — you spend more time thinking about where that field lives in the object and how much of the path needs to be recreated around it.&lt;/p&gt;

&lt;p&gt;That friction gets expensive quickly because forms are one of the most frequently updated parts of a UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The mental model gets worse as the form becomes a real product feature
&lt;/h2&gt;

&lt;p&gt;This is where the problem usually stops being “a bit annoying” and starts becoming architectural.&lt;/p&gt;

&lt;p&gt;Small forms are forgiving. Product forms are not.&lt;/p&gt;

&lt;p&gt;A form that begins with a few inputs often grows into something much more complex:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;field-level validation&lt;/li&gt;
&lt;li&gt;conditional sections&lt;/li&gt;
&lt;li&gt;repeatable groups&lt;/li&gt;
&lt;li&gt;draft saving&lt;/li&gt;
&lt;li&gt;edit flows&lt;/li&gt;
&lt;li&gt;autosave&lt;/li&gt;
&lt;li&gt;live summaries&lt;/li&gt;
&lt;li&gt;API transformations before submit&lt;/li&gt;
&lt;li&gt;role-based or account-based behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine all of that sitting on top of one deeply nested &lt;code&gt;formData&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;At that point, every new requirement has to fit into a structure that was probably designed around how the form looked in version one, not around how it behaves now.&lt;/p&gt;

&lt;p&gt;And that’s when the mental overhead increases.&lt;/p&gt;

&lt;p&gt;You’re no longer thinking only about what changed. You’re also thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where that value lives&lt;/li&gt;
&lt;li&gt;which parent objects need to be recreated&lt;/li&gt;
&lt;li&gt;which components receive that section of the form&lt;/li&gt;
&lt;li&gt;whether another part of the screen depends on the same object&lt;/li&gt;
&lt;li&gt;how much of the form is being passed around just to update one small part&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the kind of complexity that doesn’t show up immediately. It accumulates quietly, then suddenly every small change feels more expensive than it should.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. It can also become a rendering problem
&lt;/h2&gt;

&lt;p&gt;This is the part that often gets oversimplified, so it’s worth being precise.&lt;/p&gt;

&lt;p&gt;Deeply nested state does not automatically make a form slow. React is perfectly capable of handling nested objects, and not every nested update is a performance issue.&lt;/p&gt;

&lt;p&gt;But nested state &lt;em&gt;does&lt;/em&gt; make it easier to create unnecessary rendering work.&lt;/p&gt;

&lt;p&gt;When you update a deeply nested value, you create new object references along the path to that value. Any component that depends on those recreated objects may re-render, even if most of the data inside them hasn’t meaningfully changed.&lt;/p&gt;

&lt;p&gt;In a small form, that may not matter at all.&lt;/p&gt;

&lt;p&gt;In a larger product form, it starts to matter more.&lt;/p&gt;

&lt;p&gt;Think about a screen that has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple sections mounted at once&lt;/li&gt;
&lt;li&gt;inline validation running while the user types&lt;/li&gt;
&lt;li&gt;a sidebar showing a live summary&lt;/li&gt;
&lt;li&gt;conditional sections appearing based on previous answers&lt;/li&gt;
&lt;li&gt;autosave in the background&lt;/li&gt;
&lt;li&gt;reusable child components receiving slices of the form state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the cost of each update becomes more visible.&lt;/p&gt;

&lt;p&gt;Changing one field should ideally affect the smallest possible part of the UI. But when state is deeply nested, it becomes easier for that one change to ripple through larger objects than necessary.&lt;/p&gt;

&lt;p&gt;Again, the point isn’t “nested state is bad.” The point is that nested state often makes it harder to keep updates isolated.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example: where this starts hurting
&lt;/h2&gt;

&lt;p&gt;Imagine you’re building a candidate profile form for a hiring platform.&lt;/p&gt;

&lt;p&gt;The form includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;personal details&lt;/li&gt;
&lt;li&gt;current location&lt;/li&gt;
&lt;li&gt;salary expectations&lt;/li&gt;
&lt;li&gt;work experience&lt;/li&gt;
&lt;li&gt;skills&lt;/li&gt;
&lt;li&gt;education&lt;/li&gt;
&lt;li&gt;notice period&lt;/li&gt;
&lt;li&gt;portfolio and social links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, storing all of that inside one nested &lt;code&gt;formData&lt;/code&gt; object feels reasonable. It’s one candidate profile, so one object sounds perfectly fine.&lt;/p&gt;

&lt;p&gt;Then the product gets more sophisticated.&lt;/p&gt;

&lt;p&gt;Salary validation changes based on location.&lt;br&gt;
Work experience becomes repeatable and reorderable.&lt;br&gt;
Notice period influences job recommendations.&lt;br&gt;
A profile summary updates live on the side.&lt;br&gt;
Autosave runs every few seconds.&lt;br&gt;
Some fields are only shown for certain roles or account types.&lt;/p&gt;

&lt;p&gt;Now the problem isn’t whether the object looks organized.&lt;/p&gt;

&lt;p&gt;The real question is whether the state shape makes frequent, isolated changes easy to update, easy to validate, and easy to reason about.&lt;/p&gt;

&lt;p&gt;That’s the moment when the original nested structure often starts feeling expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistake is assuming data shape and state shape should always match
&lt;/h2&gt;

&lt;p&gt;This is one of the most common traps in React form design.&lt;/p&gt;

&lt;p&gt;Because the UI is grouped into sections, we assume the state should mirror those sections exactly. If the screen has an Address section, we create an &lt;code&gt;address&lt;/code&gt; object. If it has Company Details, we create a &lt;code&gt;companyDetails&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;That seems logical, and sometimes it is.&lt;/p&gt;

&lt;p&gt;But form state should not be designed only around how the data is grouped. It should also be designed around how the data changes.&lt;/p&gt;

&lt;p&gt;Those are not always the same thing.&lt;/p&gt;

&lt;p&gt;A form may be visually divided into sections, but user interaction doesn’t happen section by section. It happens one field at a time.&lt;/p&gt;

&lt;p&gt;That distinction matters more than it seems.&lt;/p&gt;

&lt;p&gt;If the most common operation in a form is “update one field,” then your state structure should make that operation cheap and obvious. If it doesn’t, there’s a good chance the state is optimized for appearance rather than behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why flatter state often works better
&lt;/h2&gt;

&lt;p&gt;A flatter state shape reduces the amount of state you need to touch for a small change.&lt;/p&gt;

&lt;p&gt;That has a few practical benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simpler updates
&lt;/h3&gt;

&lt;p&gt;Field updates stay closer to the actual change. You spend less effort recreating object paths and more effort implementing the behavior the form actually needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easier maintenance
&lt;/h3&gt;

&lt;p&gt;As validation, conditional rendering, and submission logic grow, flatter state is usually easier to debug and refactor because updates remain more localized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaner component boundaries
&lt;/h3&gt;

&lt;p&gt;When you avoid passing large nested objects through the tree, it becomes easier to split the form into focused components that only depend on the data they actually need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better control over rendering
&lt;/h3&gt;

&lt;p&gt;Flatter state doesn’t magically solve re-rendering problems, but it gives you more control over which references change and why.&lt;/p&gt;

&lt;p&gt;That said, the goal is not to flatten everything blindly.&lt;/p&gt;

&lt;p&gt;Some nesting is perfectly reasonable. If a piece of data truly belongs together, changes infrequently, and is always consumed as a group, nesting can be fine.&lt;/p&gt;

&lt;p&gt;The problem is unnecessary nesting in parts of the form that change constantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better rule of thumb: structure form state around change
&lt;/h2&gt;

&lt;p&gt;One of the most useful frontend habits is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t structure form state only around how the data looks. Structure it around how the data changes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That changes the questions you ask.&lt;/p&gt;

&lt;p&gt;Instead of only asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How should I model this form as one object?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which fields change most often?&lt;/li&gt;
&lt;li&gt;Which sections are validated independently?&lt;/li&gt;
&lt;li&gt;Which values are conditionally shown?&lt;/li&gt;
&lt;li&gt;Which parts of the form are reused in multiple places?&lt;/li&gt;
&lt;li&gt;Which updates should stay isolated from the rest of the UI?&lt;/li&gt;
&lt;li&gt;If this form doubles in size, what becomes painful first?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those questions usually lead to a more practical state shape than simply mirroring the visual structure of the form.&lt;/p&gt;

&lt;h2&gt;
  
  
  You may not notice this in a small form. You’ll notice it in a real one.
&lt;/h2&gt;

&lt;p&gt;This is why nested form state can feel harmless at first.&lt;/p&gt;

&lt;p&gt;A small demo form doesn’t put much pressure on the state structure. With a handful of fields and a single submit action, almost any approach can look fine.&lt;/p&gt;

&lt;p&gt;Production forms are different.&lt;/p&gt;

&lt;p&gt;They collect edge cases.&lt;br&gt;
They accumulate validation rules.&lt;br&gt;
They gain conditional logic, edit flows, partial saves, analytics events, and product requirements that were never part of the original plan.&lt;/p&gt;

&lt;p&gt;That’s when state design starts to matter.&lt;/p&gt;

&lt;p&gt;Not because React can’t handle nested objects.&lt;br&gt;
Not because flattening is a universal best practice.&lt;br&gt;
But because the cost of a state shape becomes visible when the form becomes a real feature rather than a tutorial example.&lt;/p&gt;

&lt;h2&gt;
  
  
  The simplest sign your form state needs a rethink
&lt;/h2&gt;

&lt;p&gt;If updating one field feels more complicated than the value of the change itself, it’s probably worth revisiting your state structure.&lt;/p&gt;

&lt;p&gt;Not because the code is ugly.&lt;br&gt;
Not because every nested object is wrong.&lt;br&gt;
But because that kind of friction tends to spread.&lt;/p&gt;

&lt;p&gt;It shows up in validation logic.&lt;br&gt;
Then in component boundaries.&lt;br&gt;
Then in rendering behavior.&lt;br&gt;
Then in future refactors.&lt;br&gt;
Then in the time it takes a new developer to understand why changing one input touches three layers of objects.&lt;/p&gt;

&lt;p&gt;That’s when a form stops being just a form problem and becomes a maintainability problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Deeply nested state often feels like an organizational win at the start of a project. It keeps related data together and mirrors the form structure nicely.&lt;/p&gt;

&lt;p&gt;But React forms are not static data models. They are interactive systems built around frequent, isolated updates.&lt;/p&gt;

&lt;p&gt;And that changes what “good structure” actually means.&lt;/p&gt;

&lt;p&gt;If a form is updated field by field, validated field by field, and rendered in pieces, then the state should support that reality.&lt;/p&gt;

&lt;p&gt;So the next time a one-line change in the UI turns into a surprisingly awkward state update, don’t just blame the syntax.&lt;/p&gt;

&lt;p&gt;Look at the shape of the state.&lt;/p&gt;

&lt;p&gt;Because in React, if updating one field feels harder than it should, the form usually isn’t the real problem. The state structure is.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>performance</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
