<?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>Forem: Marcos Vinicios da Silva Neves</title>
    <description>The latest articles on Forem by Marcos Vinicios da Silva Neves (@viniciosneves).</description>
    <link>https://forem.com/viniciosneves</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162134%2F6ee9c5fb-681d-4046-9130-2ec0cecbba82.jpg</url>
      <title>Forem: Marcos Vinicios da Silva Neves</title>
      <link>https://forem.com/viniciosneves</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/viniciosneves"/>
    <language>en</language>
    <item>
      <title>Your devs are faster with AI. Your team might not be.</title>
      <dc:creator>Marcos Vinicios da Silva Neves</dc:creator>
      <pubDate>Fri, 10 Apr 2026 13:09:53 +0000</pubDate>
      <link>https://forem.com/viniciosneves/your-devs-are-faster-with-ai-your-team-might-not-be-mc5</link>
      <guid>https://forem.com/viniciosneves/your-devs-are-faster-with-ai-your-team-might-not-be-mc5</guid>
      <description>&lt;p&gt;&lt;em&gt;How to use DORA metrics to measure the real impact of AI tools — and stop confusing speed with delivery&lt;/em&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  OK, everyone's using AI. Now what?
&lt;/h2&gt;

&lt;p&gt;I was in a conversation the other day about the real impact of AI on software development. Not the "AI will replace developers" talk — the practical one: how do we actually measure this? How do we know if these tools are genuinely improving our team's delivery?&lt;/p&gt;

&lt;p&gt;The conversation went to DORA, to productivity metrics, to ROI. And I walked away buzzing — not with doubt, but with the urge to organize all of it. This article is the result.&lt;/p&gt;

&lt;p&gt;I use AI every day. Claude Code, Cursor, Copilot, the whole stack. For my own work and for my team's. I've been sharing weekly in my newsletter how that journey has been going — what works, what doesn't, what surprises me.&lt;/p&gt;

&lt;p&gt;But using is one thing. Measuring is another.&lt;/p&gt;

&lt;p&gt;And measuring for real — with numbers, with evidence, with something you can put in a spreadsheet and show someone — is where most teams get stuck.&lt;/p&gt;

&lt;p&gt;Here's the truth: most teams today are in "adopt and hope" mode. Rolled out Copilot for everyone, maybe a Claude Code license for whoever asked, and the success metric became a vibe. "Seems faster." "People like it." "More PRs this sprint."&lt;/p&gt;

&lt;p&gt;Great. But did lead time drop? Did the change failure rate shift? Is review time the same, better, or — spoiler — worse?&lt;/p&gt;

&lt;p&gt;If you can't answer those questions, you're not alone. But you can't stay there either.&lt;/p&gt;

&lt;p&gt;In this article, I'm going to walk you through a practical plan to measure the impact of AI on your team. I'll explain what DORA metrics are (and why they matter now more than ever), show where AI actually shows up in the numbers — and where it misleads — and give you a playbook with concrete tools and metrics you can start using tomorrow. Not next week. Tomorrow.&lt;/p&gt;

&lt;p&gt;Because an opinion without data is just another opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DORA metrics are (skip if you already know)
&lt;/h2&gt;

&lt;p&gt;If you know DORA, skip ahead. No hard feelings. But if you've heard the term in a meeting and nodded along pretending you knew what it meant — stick with me. It's worth it.&lt;/p&gt;

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

&lt;p&gt;DORA stands for DevOps Research and Assessment. It's a research program that started in 2013 and now lives inside Google Cloud. Every year they publish a massive report based on surveys with thousands of teams around the world. The goal is simple: understand what makes a software team deliver well.&lt;/p&gt;

&lt;p&gt;And "deliver well" here isn't an opinion. It's metrics. Four of them, originally — now five.&lt;/p&gt;

&lt;h3&gt;
  
  
  The original four
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Deployment frequency&lt;/strong&gt; — how often your team ships to production. Not "how often we merge PRs." Deploy. To production. Running. High-performing teams do this multiple times a day. Struggling teams do it once a month, sometimes less.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lead time for changes&lt;/strong&gt; — how long it takes from commit to that code running in production. This includes everything: CI, review, QA, approval, deploy. If your commit takes 3 weeks to reach production, it doesn't matter how fast you wrote the code. Delivery is still slow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change failure rate&lt;/strong&gt; — of all the deploys you make, how many cause problems? Rollbacks, hotfixes, incidents. If you deploy 10 times a week and 3 of those break something, your change failure rate is 30%. That's terrible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MTTR (mean time to recover)&lt;/strong&gt; — when things go wrong, how long does it take to get back to normal? A team that recovers in 15 minutes lives in a different world from a team that takes 2 days.&lt;/p&gt;

&lt;p&gt;Together, these four metrics measure two things: speed (deployment frequency + lead time) and stability (change failure rate + MTTR). DORA's key insight is that elite teams are good at both. It's not "fast or stable" — it's both at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fifth metric: rework rate
&lt;/h3&gt;

&lt;p&gt;In 2024, DORA added a fifth metric: rework rate. It measures the percentage of deployments that are unplanned fixes — the patch that wasn't on the backlog, that showed up because something shipped to production wasn't quite as ready as it seemed.&lt;/p&gt;

&lt;p&gt;The difference from change failure rate is subtle but important: change failure rate catches the deploy that explodes. Rework rate catches the deploy that works, but works poorly. The bug a user reports three days later. The weird behavior nobody caught in review.&lt;/p&gt;

&lt;p&gt;Keep this metric in mind. It's going to be very important when we talk about AI-generated code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem with DORA (that nobody tells you)
&lt;/h3&gt;

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

&lt;p&gt;Now, before you rush off to build a dashboard with these five metrics: hold on.&lt;/p&gt;

&lt;p&gt;DORA on a slide looks beautiful. Four quadrants, nice colors, "elite vs low performer." You can build an entire presentation around it and walk out of the meeting to applause.&lt;/p&gt;

&lt;p&gt;But DORA in practice requires context. If you measure deployment frequency without accounting for the fact that half your deploys are config changes that don't go through review, the number lies. If your lead time is low because your team pushes straight to main without review — congratulations, your lead time is great and your production is a ticking time bomb.&lt;/p&gt;

&lt;p&gt;The metrics were designed to be read together, as a system. Speed without stability is chaos. Stability without speed is bureaucracy. Balance is what matters.&lt;/p&gt;

&lt;p&gt;And that's exactly why DORA is the right framework to measure AI impact. Because AI disrupts that entire balance — and if you only look at one metric in isolation, you'll draw the wrong conclusion.&lt;/p&gt;

&lt;p&gt;Which is exactly what's happening with most teams today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The paradox: your devs are faster, but your team isn't
&lt;/h2&gt;

&lt;p&gt;OK, now that we speak the same language about DORA, let me show you what's happening in the real world.&lt;/p&gt;

&lt;p&gt;Faros AI analyzed telemetry from over 10,000 developers across 1,255 teams. The individual numbers look great: 21% more tasks completed, 98% more PRs merged. If you stopped reading here, the conclusion is obvious — roll out AI for everyone and watch the numbers climb.&lt;/p&gt;

&lt;p&gt;Don't stop reading here.&lt;/p&gt;

&lt;p&gt;When they measured DORA on the same teams — deployment frequency, lead time, change failure rate, MTTR — nothing moved. Zero. Developers produced nearly double the PRs and team delivery stayed exactly the same.&lt;/p&gt;

&lt;p&gt;It gets worse. Anthropic ran an internal survey with 132 engineers using Claude Code. The individual results were stunning: 67% more PRs merged per day, usage jumped from 28% to 59% of daily work, self-reported productivity gains between 20% and 50%. Then someone checked the organizational dashboard. The delivery metrics hadn't moved.&lt;/p&gt;

&lt;p&gt;This has a name: AI Productivity Paradox.&lt;/p&gt;

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

&lt;p&gt;And it's not an isolated case. The 2024 DORA report was even more direct: for every 25 percentage point increase in AI adoption, delivery throughput dropped 1.5% and delivery stability dropped 7.2%. More AI, worse delivery. Read that again.&lt;/p&gt;

&lt;p&gt;The METR study with 16 experienced developers working on familiar codebases showed that developers using AI took 19% longer to complete tasks — while estimating they were 20% faster. A 39-point gap between perception and reality.&lt;/p&gt;

&lt;p&gt;So we have a scenario where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Devs write more code ✅&lt;/li&gt;
&lt;li&gt;Devs open more PRs ✅&lt;/li&gt;
&lt;li&gt;Devs &lt;em&gt;feel&lt;/em&gt; faster ✅&lt;/li&gt;
&lt;li&gt;The team delivers more value ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How is this possible? How do you double individual output and the system's result stays the same — or gets worse?&lt;/p&gt;

&lt;p&gt;The answer lies in what happens &lt;em&gt;after&lt;/em&gt; the code is written.&lt;/p&gt;

&lt;h2&gt;
  
  
  We're reviewing code with no author
&lt;/h2&gt;

&lt;p&gt;To understand the paradox, you need to look at code review. Because that's where everything jams up.&lt;/p&gt;

&lt;p&gt;Think about the pipeline: AI generates code → dev opens PR → someone reviews → merge → deploy → production → value. AI accelerated the first step. Wonderful. But the rest of the pipeline didn't change. And when you speed up one stage without speeding up the others, you don't deliver faster — you create a bigger queue at the next stage.&lt;/p&gt;

&lt;p&gt;In this case, the queue is code review. And Faros AI's numbers are brutal: while PR volume went up 98%, review time went up 91%. PRs got 154% larger. The bottleneck didn't disappear — it changed address.&lt;/p&gt;

&lt;p&gt;But the problem isn't just volume. The problem is that review changed in &lt;em&gt;nature&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before AI
&lt;/h3&gt;

&lt;p&gt;When you reviewed a colleague's code, you were evaluating someone's reasoning. You know the person, you know their level, you know how they think. Review was a conversation: "I see what you were going for here, but what if we did it this way?" You'd read the code and understand the intent behind it.&lt;/p&gt;

&lt;p&gt;The effort was naming, architecture, readability. Aesthetic and structural concerns. Important, sure — but familiar.&lt;/p&gt;

&lt;h3&gt;
  
  
  After AI
&lt;/h3&gt;

&lt;p&gt;Now you're reviewing code that nobody on the team &lt;em&gt;thought through&lt;/em&gt;. The AI wrote it, the dev glanced at it, opened the PR. The code looks right. It compiles, passes tests, follows project conventions. But "looks right" and "is right" are very different things.&lt;/p&gt;

&lt;p&gt;And that changes review completely:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From intent to factual correctness.&lt;/strong&gt; Before, it was "I get what you were trying to do." Now it's "Is this actually correct?" Because AI writes plausible code, not necessarily correct code. It's great at generating something that &lt;em&gt;looks&lt;/em&gt; like it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From author trust to zero trust.&lt;/strong&gt; Before, you knew who wrote it. Now, part of the code wasn't thought through by anyone on the team. Review becomes almost an audit — trust, but verify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From reading to mental simulation.&lt;/strong&gt; Before, you'd read the code and follow the flow. Now you need to imagine: unexpected inputs, weird state, integrations breaking. Review became more about executing the code in your head than reading it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From improving to detecting risk.&lt;/strong&gt; Before, it was refactoring suggestions, clean code, better naming. Now it's "could this cause a problem?", "does this scale?", "does this open a security hole?" Priority shifted from aesthetic quality to risk mitigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From diff to system.&lt;/strong&gt; Without adequate context, AI tends to ignore project patterns, duplicate existing logic, and create isolated solutions. Good specs and well-crafted prompts reduce this significantly — but most teams aren't there yet. Until they are, the reviewer foots the bill: they're no longer just reviewing the diff, they're verifying whether it fits the rest of the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From review to rubber stamp.&lt;/strong&gt; And then there's the scenario nobody likes to admit: the dev gets the PR, sees it's large, sees it was AI-generated, and approves without really reading it. "The AI made it, must be fine." PR volume is already high, review is already heavier, and the temptation to drop a quick LGTM and move on is real. When that happens, review stops existing as a quality filter — and everything we've discussed about change failure rate and rework rate becomes a direct consequence.&lt;/p&gt;

&lt;h3&gt;
  
  
  The invisible effect
&lt;/h3&gt;

&lt;p&gt;All of this together explains why review takes longer, is more draining, and demands more seniority. Because now you need to &lt;em&gt;think&lt;/em&gt; more than &lt;em&gt;read&lt;/em&gt;. The cognitive effort is fundamentally different.&lt;/p&gt;

&lt;p&gt;And the data backs up what we feel in practice. Stack Overflow's 2025 survey shows developer trust in AI tool accuracy dropped from 40% to 29% in a single year. 66% of developers say AI-generated code is "almost right, but not quite" — and that "almost" is exactly what makes review harder. Completely wrong code fails fast. Almost-right code passes tests and breaks in production three weeks later.&lt;/p&gt;

&lt;p&gt;Sonar's survey of over 1,100 developers surfaced the most worrying number: 96% of developers don't trust that AI-generated code is functionally correct. But only 48% say they always review before committing. Read that again: almost everyone is skeptical, but half don't verify. There's a name for this: &lt;em&gt;verification debt&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The review workarounds
&lt;/h3&gt;

&lt;p&gt;And then there's the second problem: how teams are trying to solve this.&lt;/p&gt;

&lt;p&gt;Some people copy the PR diff, paste it into ChatGPT or Claude, and treat the response as a completed review. Others connect an MCP, point the AI at the code and say "review this." And yes, it catches things — bad naming, unused imports, sometimes even an obvious bug.&lt;/p&gt;

&lt;p&gt;But that's not code review. That's lint with better marketing.&lt;/p&gt;

&lt;p&gt;The AI doing the review doesn't know your system's context. It doesn't know that service has an implicit contract with another module. It doesn't know that pattern was an architectural decision your team made for a specific reason. It sees the diff in isolation — which is exactly the "diff vs system" problem we already discussed.&lt;/p&gt;

&lt;p&gt;Using AI as a &lt;em&gt;first filter&lt;/em&gt; before human review? Excellent. Tools like Claude Code Review and CodeRabbit do exactly that — they handle the mechanical stuff so the human reviewer can focus on the cognitive stuff. But using AI as a &lt;em&gt;replacement&lt;/em&gt; for human review is trading a bottleneck for a blind spot.&lt;/p&gt;

&lt;h3&gt;
  
  
  What this does to the metrics
&lt;/h3&gt;

&lt;p&gt;And this creates a direct side effect:&lt;/p&gt;

&lt;p&gt;Writing time ↓ Review time ↑ Lead time... doesn't change.&lt;/p&gt;

&lt;p&gt;Or worse: it gets longer.&lt;/p&gt;

&lt;p&gt;Code review stopped being a conversation between developers and became a process of validating generated code. The main job is no longer understanding intent — it's ensuring correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI doesn't remove the bottleneck — it moves the bottleneck
&lt;/h2&gt;

&lt;p&gt;Let's zoom out and look at the whole system.&lt;/p&gt;

&lt;p&gt;Before AI, most teams' bottleneck was writing code. It was slow. It required focus. There was always that task sitting in "in progress" for three days because it was complex, because the dev got stuck, because it needed research. Writing was the slowest point in the pipeline.&lt;/p&gt;

&lt;p&gt;AI solved that. Writing got fast. Sometimes absurdly fast.&lt;/p&gt;

&lt;p&gt;But the pipeline didn't shrink — the weight just shifted. Now the slowest point is reviewing, validating, and testing. And this is so predictable it already has a name in the literature: &lt;strong&gt;Verification Tax&lt;/strong&gt;. The cost of verifying what the AI produced.&lt;/p&gt;

&lt;p&gt;Think about it this way: if your team had a 100-hour pipeline and 40 of those hours were writing code, AI might have cut those 40 down to 15. Great. But if the 30 hours of review turned into 50 because volume doubled and review complexity increased, the total went from 100 to... 95. Five hours gained. Not exactly the miracle the slide promised.&lt;/p&gt;

&lt;p&gt;And then you go back to DORA metrics and the question that actually matters:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Did this increase in output translate to improvement in delivery?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In most cases, the answer is no. Deployment frequency didn't go up because the bottleneck is now review, not writing. Lead time didn't drop because code reaches the PR faster but sits longer waiting for approval. Change failure rate might even get worse if overloaded review lets things slip through. And rework rate — remember the fifth metric? — goes up because "almost right" code generates fix after fix.&lt;/p&gt;

&lt;p&gt;The 2025 DORA report sums this up in a way that stings: AI works as a mirror and amplifier. If the team already has good processes, AI accelerates them. If the team already has problems, AI amplifies the problems. It doesn't fix anything — it exposes what was already there.&lt;/p&gt;

&lt;p&gt;And that's why measuring only individual output is so dangerous. The dev looks at their own work and thinks "I'm flying." The tech lead looks at the board and thinks "why hasn't velocity changed?" They're both right. They're both looking at different metrics.&lt;/p&gt;

&lt;p&gt;The right question isn't "are my devs more productive?" It's "is my team delivering more value?" And to answer that, you need a playbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  The playbook: how to start measuring tomorrow
&lt;/h2&gt;

&lt;p&gt;Enough concepts. This is where we get operational. I'm going to give you a four-week plan with concrete tools. Adapt it to your context, but the structure works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 1: create your baseline
&lt;/h3&gt;

&lt;p&gt;Before measuring the impact of anything, you need to know where you stand today. Without a baseline, any number you pull later is meaningless — you have nothing to compare against.&lt;/p&gt;

&lt;p&gt;What to measure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lead time&lt;/strong&gt; — from first commit to deploy in production. If you use GitHub Actions for deployment, GitHub Insights already shows part of this. For a more complete picture, Apache DevLake (open source, self-hosted) connects with GitHub, GitLab, and Jira and gives you a ready-made DORA dashboard. If your team already uses Datadog, the DORA Metrics module integrates directly with your CI/CD pipeline and correlates with infrastructure data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment frequency&lt;/strong&gt; — how many deploys per week your team ships. Same tools: DevLake or Datadog pull this automatically from your pipelines. For something simpler, Four Keys from Google's own DORA team (open source) does exactly this from GitHub events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change failure rate&lt;/strong&gt; — percentage of deploys that cause problems in production. I need to be honest here: to measure this, you need some form of incident management. And if your team doesn't do that today, that's OK — many teams don't. But it's time to start.&lt;/p&gt;

&lt;p&gt;You don't need an expensive tool on day one. Start simple: create a Slack channel (something like #incidents), agree with the team that every rollback, hotfix, or production issue gets a message there with a date, description, and resolution time. That's incident management. Basic, manual, but it's real data.&lt;/p&gt;

&lt;p&gt;As that process matures, then it's worth looking at tools like PagerDuty, Opsgenie, or even GitHub Issues with incident labels. DevLake and LinearB integrate with these sources and calculate change failure rate automatically. But Slack with discipline already gives you the number that matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MTTR&lt;/strong&gt; — time between the problem appearing and the service returning to normal. If you followed the advice above and created the incidents channel, you already have what you need: the time the message was posted and the time someone replied "resolved." The difference between those two is your MTTR. As your process evolves, incident management tools calculate this automatically — but the starting point is the same manual log.&lt;/p&gt;

&lt;p&gt;You don't need perfection here. You need an honest snapshot of the last 2–3 months. Pull the data, put it in a spreadsheet, and save it. That's your "before" photo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 2: measure the PR flow
&lt;/h3&gt;

&lt;p&gt;Now you go one level deeper and look at where AI actually shows up — in the daily work of writing code. This is where the impact (or the illusion of impact) becomes visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PR cycle time&lt;/strong&gt; — time from PR open to merge. GitHub has the Issue Metrics Action (free, maintained by GitHub) that measures time to first response and time to close. Configure it once and it runs on whatever schedule you want. If you need more detail, the Pull Request Analytics Action breaks the cycle into stages: development time, reviewer response time, review time, integration time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time to first review&lt;/strong&gt; — how long the PR sits waiting for someone to look at it. If this number is climbing, you already have evidence of a review bottleneck. The Issue Metrics Action gives you this for free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review load per dev&lt;/strong&gt; — how many PRs each person reviews per week and how many lines per review. This reveals saturation. Graphite Insights shows this in a visual dashboard. If you don't want a paid tool, the Pull Request Analytics Action generates per-dev reports with review volume and engagement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PR size&lt;/strong&gt; — lines added per PR. Remember the 154% increase from the Faros AI study? Microsoft's PR Metrics Action (open source) adds automatic size labels to the PR title — XS, S, M, L, XL. Simple, visual, and everyone on the team sees it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 3: compare the two photos
&lt;/h3&gt;

&lt;p&gt;Now you have two data sets: the system-level DORA metrics and the day-to-day PR metrics. The question you ask here is simple:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"We're producing more code, more PRs, faster. But are we delivering more?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Cross-reference them. If PR throughput went up but deployment frequency stayed flat, the gains are dying between the PR and production. If PR cycle time went up while writing time went down, the bottleneck moved — exactly what we discussed earlier.&lt;/p&gt;

&lt;p&gt;You don't need a sophisticated tool here. You need a spreadsheet with two columns side by side and the honesty to read what the numbers say.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 4: identify the new bottleneck
&lt;/h3&gt;

&lt;p&gt;With the data from previous weeks, you'll be able to pinpoint where the pipeline is jamming. And the spoiler is almost always one of these:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt; — if time to first review and review cycle time are climbing, the bottleneck is review. Action: consider automated review as a first filter (Claude Code Review, GitHub Copilot code review, CodeRabbit), limit PR size, distribute review load better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QA/Tests&lt;/strong&gt; — if change failure rate is climbing or rework rate is high, code is reaching production with problems. Action: more automated test coverage, quality gates in CI before merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy&lt;/strong&gt; — if PRs merge fast but deployment frequency doesn't rise, the bottleneck is in the deploy pipeline. Action: this isn't an AI problem, it's an infrastructure and process problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real talk on tools
&lt;/h3&gt;

&lt;p&gt;I'll be direct: if you want to start tomorrow at zero cost, go with &lt;strong&gt;Apache DevLake&lt;/strong&gt; for DORA metrics and &lt;strong&gt;Issue Metrics Action + PR Metrics Action&lt;/strong&gt; for PR flow. All open source, all integrate with GitHub.&lt;/p&gt;

&lt;p&gt;If you have budget and want something more integrated, &lt;strong&gt;LinearB&lt;/strong&gt; and &lt;strong&gt;Swarmia&lt;/strong&gt; combine DORA with developer experience metrics and give you ready-made dashboards.&lt;/p&gt;

&lt;p&gt;If you already use &lt;strong&gt;Datadog&lt;/strong&gt;, activate the DORA Metrics module — it's right there, and you're probably paying for it without knowing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What no tool can solve
&lt;/h3&gt;

&lt;p&gt;Now, the disclaimer that matters: this is not a silver bullet.&lt;/p&gt;

&lt;p&gt;Every team has its own context. Your pipeline, your review process, your deploy culture, your test maturity — all of this changes how the numbers behave and what they mean. A team that uses feature flags and continuous deploy lives in a different reality from a team that does biweekly releases with manual QA.&lt;/p&gt;

&lt;p&gt;Tools measure. You interpret. And you adapt to your context too.&lt;/p&gt;

&lt;p&gt;The playbook gives you the structure. The numbers give you the evidence. But the decision of what to do with it? That's on the tech lead, the manager, the team. No dashboard replaces judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI ROI: the math almost everyone gets wrong
&lt;/h2&gt;

&lt;p&gt;If you've made it this far, you've probably already spotted where most people go wrong calculating AI tool ROI. But let me make it explicit, because this is the part that ends up on the C-level's slide.&lt;/p&gt;

&lt;p&gt;The naive math goes like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ROI = (productivity gain − tool cost) / tool cost&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And "productivity gain" is usually calculated like: "our devs save 3–4 hours per week, we have 20 devs, that's 60–80 hours per week, at an average cost of X per hour, we're saving Y per month." Subtract the license cost, divide, and you're done — positive ROI. Everyone's happy.&lt;/p&gt;

&lt;p&gt;The problem is that those 3–4 hours saved on writing code didn't disappear from the system. They reappeared in review, validation, and debugging of code that nobody on the team actually wrote. The time was redistributed, not eliminated.&lt;/p&gt;

&lt;p&gt;If your DORA metrics haven't improved — if deployment frequency didn't go up, if lead time didn't drop, if change failure rate didn't decrease — then the individual gain didn't become an organizational gain. And organizational ROI is what pays the bills.&lt;/p&gt;

&lt;p&gt;That doesn't mean ROI is zero. It means the math needs to be more honest. A few things that rarely make it into the calculation but should:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cost of additional review.&lt;/strong&gt; If your seniors are spending 91% more time reviewing PRs, that time is coming from somewhere — mentorship, architecture, technical planning. What's the value of what they're &lt;em&gt;not&lt;/em&gt; doing?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cost of rework.&lt;/strong&gt; If rework rate went up, every unplanned fix is work that wasn't on the backlog. It's invisible cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cost of the learning curve.&lt;/strong&gt; Teams need time to learn to use AI effectively — good specs, good prompts, good workflows. That initial investment rarely appears on the ROI spreadsheet.&lt;/p&gt;

&lt;p&gt;The more honest math isn't "how much time did the dev save writing code." It's "how much more value did my team deliver to production after adopting the tool." And that answer comes from DORA metrics, not from satisfaction surveys.&lt;/p&gt;

&lt;p&gt;If DORA improved: congrats, your ROI is real. If DORA stayed flat: your team is faster at the wrong stage. If DORA got worse: you're paying to create problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The only sentence that matters
&lt;/h2&gt;

&lt;p&gt;If you read this entire article, thank you. If you skipped everything and landed here, no judgment — at least take this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI optimizes the individual. DORA measures the system. And the system ≠ the sum of its individuals.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your dev is faster. Your team might not be. And until you measure the system, you won't know the difference.&lt;/p&gt;

&lt;p&gt;Now you have the metrics, the tools, and the playbook. What's left is to open the spreadsheet and start. Tomorrow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools mentioned in this article
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Metrics and observability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://devlake.apache.org/" rel="noopener noreferrer"&gt;Apache DevLake&lt;/a&gt; — Open source engineering metrics platform. Connects with GitHub, GitLab, and Jira, ships with a ready-made DORA dashboard. Self-hosted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/dora-team/fourkeys" rel="noopener noreferrer"&gt;Four Keys&lt;/a&gt; — Open source project from Google's DORA team. Collects events from GitHub/GitLab and calculates the four DORA metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://linearb.io/" rel="noopener noreferrer"&gt;LinearB&lt;/a&gt; — Paid platform combining DORA metrics with developer experience and workflow automation (gitStream). Integrates with GitHub, GitLab, Jira, and incident tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.swarmia.com/" rel="noopener noreferrer"&gt;Swarmia&lt;/a&gt; — Paid platform with DORA, SPACE, and investment metrics (features vs. maintenance vs. bugs). Good Slack integration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.datadoghq.com/dora_metrics/" rel="noopener noreferrer"&gt;Datadog DORA Metrics&lt;/a&gt; — DORA module inside Datadog. If you already use Datadog for observability, just turn it on — it correlates delivery metrics with infrastructure data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PR and code review metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/github/issue-metrics" rel="noopener noreferrer"&gt;GitHub Issue Metrics Action&lt;/a&gt; — Official free GitHub Action. Measures time to first response, time to close, and generates automatic reports as repo issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/pull-request-analytics" rel="noopener noreferrer"&gt;Pull Request Analytics Action&lt;/a&gt; — Free GitHub Action that generates detailed review reports: review cycle, load per dev, engagement, and stalled PRs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/pr-metrics" rel="noopener noreferrer"&gt;Microsoft PR Metrics Action&lt;/a&gt; — Open source GitHub Action from Microsoft. Adds automatic size labels (XS to XL) and test coverage indicators to PR titles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://graphite.dev/" rel="noopener noreferrer"&gt;Graphite Insights&lt;/a&gt; — Visual PR metrics dashboard: merged PRs, review load per dev, cycle time. Paid with free tier.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Automated code review&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://claude.com/blog/code-review" rel="noopener noreferrer"&gt;Claude Code Review&lt;/a&gt; — Multi-agent automated review from Anthropic. Runs on each PR, identifies bugs and ranks by severity. Doesn't approve — leaves the decision to the human.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://coderabbit.ai/" rel="noopener noreferrer"&gt;CodeRabbit&lt;/a&gt; — AI-powered automated review that analyzes PRs and suggests improvements. Integrates with GitHub and GitLab.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Incident management&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pagerduty.com/" rel="noopener noreferrer"&gt;PagerDuty&lt;/a&gt; — Incident management and on-call platform. Integrates with DevLake and LinearB to calculate change failure rate and MTTR automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.atlassian.com/software/opsgenie" rel="noopener noreferrer"&gt;Opsgenie&lt;/a&gt; — Incident management and alerting from Atlassian. Same integrations as PagerDuty for DORA metric calculation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Faros AI — &lt;em&gt;The AI Productivity Paradox: Key Takeaways from the DORA Report 2025&lt;/em&gt;. Telemetry analysis of 10,000+ devs across 1,255 teams. &lt;a href="https://www.faros.ai/blog/key-takeaways-from-the-dora-report-2025" rel="noopener noreferrer"&gt;faros.ai/blog/key-takeaways-from-the-dora-report-2025&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anthropic — &lt;em&gt;How AI Is Transforming Work at Anthropic&lt;/em&gt;. Internal survey with 132 engineers on Claude Code usage. &lt;a href="https://www.anthropic.com/research/how-ai-is-transforming-work-at-anthropic" rel="noopener noreferrer"&gt;anthropic.com/research/how-ai-is-transforming-work-at-anthropic&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;METR — &lt;em&gt;Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity&lt;/em&gt;. RCT with 16 devs and 246 tasks. &lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Google Cloud — &lt;em&gt;2025 DORA State of AI-Assisted Software Development Report&lt;/em&gt;. &lt;a href="https://cloud.google.com/resources/content/2025-dora-ai-assisted-software-development-report" rel="noopener noreferrer"&gt;cloud.google.com/resources/content/2025-dora-ai-assisted-software-development-report&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DORA — &lt;em&gt;Balancing AI Tensions: Moving from AI Adoption to Effective SDLC Use&lt;/em&gt;. Qualitative analysis of 1,110 responses from Google engineers. &lt;a href="https://dora.dev/insights/balancing-ai-tensions/" rel="noopener noreferrer"&gt;dora.dev/insights/balancing-ai-tensions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stack Overflow — &lt;em&gt;2025 Developer Survey&lt;/em&gt;. Survey with 49,000+ developers on AI adoption and trust. &lt;a href="https://stackoverflow.blog/2025/12/29/developers-remain-willing-but-reluctant-to-use-ai-the-2025-developer-survey-results-are-here/" rel="noopener noreferrer"&gt;stackoverflow.blog/2025/developer-survey&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sonar — &lt;em&gt;State of Code Developer Survey Report 2026&lt;/em&gt;. Survey with 1,149 developers on AI-generated code verification. &lt;a href="https://www.sonarsource.com/state-of-code-developer-survey-report.pdf" rel="noopener noreferrer"&gt;sonarsource.com/state-of-code-developer-survey-report&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>management</category>
      <category>productivity</category>
    </item>
    <item>
      <title>React: Mastering custom Hooks and optimizing logic reusability</title>
      <dc:creator>Marcos Vinicios da Silva Neves</dc:creator>
      <pubDate>Thu, 05 Oct 2023 17:28:37 +0000</pubDate>
      <link>https://forem.com/viniciosneves/react-mastering-custom-hooks-and-optimizing-logic-reusability-10i5</link>
      <guid>https://forem.com/viniciosneves/react-mastering-custom-hooks-and-optimizing-logic-reusability-10i5</guid>
      <description>&lt;p&gt;Hey there! Yes, I'm talking to you! The one reading this article and wondering: "What on Earth are Custom Hooks, and why should I care about them?". Well, strap in, because I'm about to take you on a journey that goes beyond the traditional React Hooks. Ready to dive deep and uncover the magic behind Custom Hooks, and better yet, when to use these bad boys as opposed to our beloved pure functions?&lt;/p&gt;

&lt;p&gt;Many developers find themselves at a crossroads, trying to decide between implementing a Custom Hook or simply crafting a pure function. And, to be honest, this decision can seem baffling at first glance. But fear not, I'm here to guide the way! In this article, we'll not only unravel the enigmatic Custom Hooks, but we'll also delve into their states and, most crucially, the ideal scenarios to choose between them and pure functions. So, if you're looking to optimize and elevate your React code to a whole new level, you've come to the right place. Shall we? &lt;/p&gt;

&lt;h2&gt;
  
  
  Talk is cheap, show me the code!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yXmB-lto--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/W0DwukIXlskAAAAd/programming.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yXmB-lto--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/W0DwukIXlskAAAAd/programming.gif" alt="Someone happy and surprised by getting a new error message while debugging a code" width="640" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's kick things off with a hands-on example, one you've likely encountered or will eventually face in your developer journey. Picture a component that needs to notify a user whether they're connected to the internet or not. Sounds simple, right? Let's dive into the code:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ConnectionChecker&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;isOnline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsOnline&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onLine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;setIsOnline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onLine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOnline&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;You're online! 🌐&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Oops! You're offline... 😔&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This component, aided by &lt;code&gt;useEffect&lt;/code&gt;, checks if the browser is online or offline, and based on that information, displays a message to the user. It works wonderfully!&lt;/p&gt;

&lt;p&gt;Now, envision wanting to integrate this very logic into multiple other components within your app. Are you going to copy and paste? Absolutely not! This brings us to a pivotal question: How can we reuse this logic?&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring for Reusability
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcrrPaZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf3oq8rjyx8zsmx0uzzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcrrPaZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sf3oq8rjyx8zsmx0uzzt.png" alt="A running cat" width="640" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first glance, one might assume the most straightforward solution would be to extract the logic into a pure function. That's usually a great instinct when refactoring: identify repeated or extractable logic, put it into its separate function, and call that function where needed. But here's the catch when it comes to React: the Rules of Hooks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  The Rules of Hooks
&lt;/h3&gt;

&lt;p&gt;Before we proceed, let's briefly revisit these rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Only Call Hooks at the Top Level&lt;/strong&gt;: You can't call Hooks inside loops, conditions, or nested functions. They should always be used at the top level of your React functions. This ensures hooks are called in the same order each time a component renders, preserving the state between multiple &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Only Call Hooks from React Functions&lt;/strong&gt;: Hooks can only be called inside the body of a function component or a custom hook.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, why do these rules exist? They're not just there to be a hurdle. They ensure that your components maintain a predictable order of execution, making your components more readable, maintainable, and less prone to unexpected bugs.&lt;/p&gt;

&lt;p&gt;Given these rules, if we attempt to extract the logic in a pure function, we'd hit a wall. We're dealing with a useEffect and useState inside our logic – both of which are hooks and thus must adhere to the Rules of Hooks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating our Custom Hook
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rTmJz8uG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ngv2w7a94mamj64eqs5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rTmJz8uG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ngv2w7a94mamj64eqs5j.png" alt="Captain hook" width="498" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of a pure function, this is a perfect situation to create a custom hook. Let's dive in:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useConnectionStatus&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;isOnline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsOnline&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onLine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;setIsOnline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onLine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isOnline&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;Notice how we've extracted the logic that checks the online status into a hook named &lt;code&gt;useConnectionStatus&lt;/code&gt;. Now, let's refactor our original component to utilize this new custom hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useConnectionStatus&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./path-to-your-hook/useConnectionStatus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ConnectionChecker&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;isOnline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useConnectionStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOnline&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;You're online! 🌐&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Oops! You're offline... 😔&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With that refactor, not only have we made our component cleaner, but we've also created a piece of reusable logic that can be utilized across numerous components or even other projects. This, my friend, is the power and elegance of custom hooks!&lt;/p&gt;

&lt;h2&gt;
  
  
  Leveling Up: Advanced Custom Hooks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pdO5QriI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0thnb15ep8zrn4i0t7mh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pdO5QriI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0thnb15ep8zrn4i0t7mh.png" alt="Goku leveling up" width="498" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, you're eager to dive deeper, huh? Alright, strap in! Once we master the basics of custom hooks, we often find ourselves in trickier waters. Sometimes, this complexity demands that our hook returns a function, ensuring the component using it has more control or dynamism. Let's unravel this with a hands-on example.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Context
&lt;/h3&gt;

&lt;p&gt;Imagine you're crafting a modal component. This modal needs to show or hide based on user actions, like a button click. Moreover, perhaps we want to pass some specific content to the modal every time we display it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Custom Hook
&lt;/h3&gt;

&lt;p&gt;Let's craft a hook named &lt;code&gt;useModal&lt;/code&gt;. It'll manage the modal's visibility state and also allow setting the modal's content:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useModal&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;isVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;closeModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;setIsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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="nx"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;closeModal&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;Notice the twist! Beyond managing the visibility state (&lt;code&gt;isVisible&lt;/code&gt;) and the content (content), we're returning two functions (&lt;code&gt;showModal&lt;/code&gt; and &lt;code&gt;closeModal&lt;/code&gt;). This unlocks amazing flexibility. We can define the modal's content on-the-fly when we pop it up using showModal, or simply use it to showcase the modal with predefined content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Hook
&lt;/h3&gt;

&lt;p&gt;Let's see how this hook fits into a component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useModal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./path-to-your-hook/useModal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;isVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;closeModal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&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="nx"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, I&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;)}&amp;gt;
                Display Modal
            &amp;lt;/button&amp;gt;

            {isVisible &amp;amp;&amp;amp; (
                &amp;lt;div className="modal"&amp;gt;
                    &amp;lt;p&amp;gt;{content}&amp;lt;/p&amp;gt;
                    &amp;lt;button onClick={closeModal}&amp;gt;Close&amp;lt;/button&amp;gt;
                &amp;lt;/div&amp;gt;
            )}
        &amp;lt;/div&amp;gt;
    );
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we just pulled off is nothing short of magical! With our &lt;code&gt;useModal&lt;/code&gt; hook, we've transformed a typical logic (managing a modal's visibility and content) into something reusable, agile, and most importantly, compliant with the Rules of Hooks. This way, you retain direct control of your app's logic within the component but without sprinkling repetitive code everywhere.&lt;/p&gt;

&lt;p&gt;This showcases that custom hooks are not just about encapsulation but also about empowering and granting flexibility to your components. Hence, you build cleaner, more organized, and efficient React apps! &lt;/p&gt;

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

&lt;p&gt;Feeling pumped up about the limitless opportunities custom hooks offer? I certainly hope so! Through this deep dive into the React cosmos, we've unearthed how to turn repetitive logics into reusable marvels without breaking the sacred rules of hooks. With this newfound knowledge, the sky is merely the beginning! &lt;/p&gt;

&lt;p&gt;Now, before you jet off to experiment (and I'm pretty sure you're itching to!), swing by my dev.to profile and give me a follow! I'm continually unraveling the intricacies of the coding world and sharing all the gems right there. And if this article resonated with you, don't forget to hit that like button! &lt;/p&gt;

&lt;p&gt;Here's a special request: Drop a comment below with topics you'd love for me to tackle, lingering questions, constructive feedback, or even some good ol' praise (come on, who doesn't appreciate that?). Your insights are the pure fuel driving my next articles.&lt;/p&gt;

&lt;p&gt;Until next time, always remember: knowledge is a journey, and I'm here to guide the way! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GIE2R08E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/O2kCSg8GkW0AAAAC/stickergiant-like-and-subscribe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GIE2R08E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://media.tenor.com/O2kCSg8GkW0AAAAC/stickergiant-like-and-subscribe.gif" alt="Like and subscribe!" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>Elegant composition: Uncover the power of Tailwind CSS</title>
      <dc:creator>Marcos Vinicios da Silva Neves</dc:creator>
      <pubDate>Fri, 29 Sep 2023 11:18:58 +0000</pubDate>
      <link>https://forem.com/viniciosneves/elegant-composition-uncover-the-power-of-tailwind-css-2248</link>
      <guid>https://forem.com/viniciosneves/elegant-composition-uncover-the-power-of-tailwind-css-2248</guid>
      <description>&lt;p&gt;Welcome to this deep dive into the universe of Tailwind CSS! If you, just like me, are continually on the lookout for tools that enhance our workflow and elevate our web development projects to a new level, then you are in the right place. In this article, we will explore together the nooks and crannies of Tailwind, a CSS framework that has been winning hearts and minds in the development community.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsavaslabs.com%2Fsites%2Fdefault%2Ffiles%2Fstyles%2Fopen_graph%2Fpublic%2F2020-02%2Ftailwindcss-1000by665-2a13c5-3.jpg%3Fitok%3D-J_OGUYg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsavaslabs.com%2Fsites%2Fdefault%2Ffiles%2Fstyles%2Fopen_graph%2Fpublic%2F2020-02%2Ftailwindcss-1000by665-2a13c5-3.jpg%3Fitok%3D-J_OGUYg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we move forward, have you ever stopped to think about the journey of a framework until it becomes an indispensable tool? Well, let's start from the beginning, unraveling the origin and unique proposition of Tailwind. We will understand why it has gained so much space in the market, facing giants and standing out as a reliable and flexible option to style our applications.&lt;/p&gt;

&lt;p&gt;Throughout this article, we will dissect how Tailwind operates, addressing its strengths, its limitations, and, of course, how we can make the most of this tool in our projects. And for those who are always seeking a little more, I will guide you through setting up a Next.js project using Tailwind, detailing each step and demystifying the Tailwind config.&lt;/p&gt;

&lt;p&gt;So, are you ready to embark on this journey of discovery and deepening into Tailwind CSS? Let's go together; I am sure it will be an enriching experience, and by the end, you will feel more equipped to make informed decisions about using this tool in your future projects. Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  First steps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FctiAFSdN_foAAAAC%2Fthe-mandalorian-the-child.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FctiAFSdN_foAAAAC%2Fthe-mandalorian-the-child.gif" alt="Baby Yoda walking"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tailwind CSS operates on an intriguing concept that might seem a bit peculiar at first glance, but in practice, proves to be immensely powerful. This is the principle of class composition to craft visual components.&lt;/p&gt;

&lt;p&gt;Let’s start with a basic example. Suppose you wish to create a button with a blue background and white text. With Tailwind, it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Document&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.tailwindcss.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-blue-500 text-white px-4 py-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
       Click me!
    &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down what’s happening here. Each class you add to the element defines an aspect of the style:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bg-blue-500&lt;/code&gt;: Sets the background color of the button to a specific shade of blue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text-white&lt;/code&gt;: Sets the text color to white.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;px-4&lt;/code&gt;: Adds a horizontal padding of 4 units.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;py-2&lt;/code&gt;: Adds a vertical padding of 2 units.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how Tailwind operates! It provides many utility classes that you compose directly in your HTML to style the elements. This approach allows for very rapid visual development since you can see the changes in real-time without switching between CSS and HTML files.&lt;/p&gt;

&lt;p&gt;Now, for a more complex example, imagine a card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Document&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.tailwindcss.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:flex-shrink-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-96 w-full object-cover md:w-96"&lt;/span&gt;
                    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.wargamer.com/wp-content/sites/wargamer/2022/09/baldurs-gate-3-shadowheart-cleric.jpg"&lt;/span&gt;
                    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"uppercase tracking-wide text-sm text-indigo-500 font-semibold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Shadowheart&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block mt-1 text-lg leading-tight font-medium text-black hover:underline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    A Baldur's Gate 3 character
                &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-2 text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    Like all the companions in the DnD Game, Baldur's Gate 3 Shadowheart is a complex hero with a story
                    waiting to be uncovered. The dark-haired Cleric is secretive and more than a little sarcastic, but
                    she can also be a cooperative and capable member of your adventuring party.
                &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unleashing the Power: Tailwind with Next.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FJ6LI134YYZwAAAAd%2Fdragon-ball-z-goten.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FJ6LI134YYZwAAAAd%2Fdragon-ball-z-goten.gif" alt="Goten + Trunks fusion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unleashing the Power: Tailwind with Next.js&lt;br&gt;
One of the reasons Tailwind CSS has been widely embraced is its powerful synergy with React. Let’s illustrate this by creating a detailed React component. Imagine we want a sophisticated image component that zooms in when hovered over.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ImageZoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"transform transition-transform duration-300 hover:scale-110"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"w-full h-auto object-cover"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this piece of code, we’ve used Tailwind classes to manage the hover state and scaling of the image, making it increase to 110% of its original size with a smooth transition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js +  Tailwind
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2Fcq2hRBBPwaQAAAAC%2Ftheres-always-room-for-family-family-first.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2Fcq2hRBBPwaQAAAAC%2Ftheres-always-room-for-family-family-first.gif" alt="Fast and Furious - family"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, moving forward, let’s discuss how Next.js and Tailwind combine forces for optimized web development. The Next.js community has welcomed Tailwind with open arms, and integrating it into your project can significantly enhance your application. This is where &lt;code&gt;tailwind.config.js&lt;/code&gt; becomes a crucial player. It allows us to customize our build, catering to the specific needs of our project.&lt;/p&gt;

&lt;p&gt;Here's an example of how you might configure &lt;code&gt;tailwind.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;purge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// or 'media' or 'class'&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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="na"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this configuration, the &lt;strong&gt;purge&lt;/strong&gt; option is set to remove unused styles in production, contributing to a smaller and more efficient final bundle. This is just a glimpse into how Tailwind and Next.js can be fine-tuned to work seamlessly together, offering a highly optimized, developer-friendly experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2Fu73m7ptH6cgAAAAC%2Fkowalski-analysis-thinking.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2Fu73m7ptH6cgAAAAC%2Fkowalski-analysis-thinking.gif" alt="Fast and Furious - family"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we delve into the numerous benefits of Tailwind, it's prudent to also cast an eye on some of its downsides. A common critique is that, when using Tailwind, our HTML files can become quite verbose, leading to less clean and harder-to-read code. Moreover, there's a learning curve to get used to the utility classes, and initially, you might find yourself frequently consulting the documentation.&lt;/p&gt;

&lt;p&gt;However, once these initial hurdles are overcome, the benefits of Tailwind start to shine brightly. The freedom of styling, the speed in development, and optimized performance are aspects that have developers around the globe opting for Tailwind. Its proposition of utility classes offers a level of customization and reusability that is hard to match.&lt;/p&gt;

&lt;p&gt;The pairing with Next.js has proven to be a robust combination, enabling the creation of rich and performative interfaces. With Next.js, Tailwind gains even more ground, allowing for style optimization and more efficient build generation.&lt;/p&gt;

&lt;p&gt;Nowadays, the presence of Tailwind in Next.js applications has become quite common, and undoubtedly, dedicating some time to delve deeper into this library can prove to be a wise choice. After all, being equipped with the right tools and the knowledge to use them is fundamental to navigate with confidence in the vast ocean of front-end development. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FY-_1mRH6s9AAAAAC%2Fchiru-waltair.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FY-_1mRH6s9AAAAAC%2Fchiru-waltair.gif" alt="Fast and Furious - family"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh, before wrapping up, let me share a little tidbit with you! This is my maiden voyage into posting on dev.to, and I'm buzzing to hear what you think. So, if you could, drop some sweet feedback in the comments, alright? And, of course, don’t forget to hit that follow button to stay tuned for fresh frontend content! 🚀&lt;/p&gt;

&lt;p&gt;I’m all ears for topic suggestions and would love to hear your thoughts in the comments. Let’s build a cozy corner of learning and exchanging experiences together! Catch you &lt;strong&gt;next&lt;/strong&gt; time, and let’s get coding! 💻🎉&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
