<?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: Joodi</title>
    <description>The latest articles on DEV Community by Joodi (@joodi).</description>
    <link>https://dev.to/joodi</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%2F1320259%2F2954b0e0-8317-4bda-bad6-846087f55a96.jpg</url>
      <title>DEV Community: Joodi</title>
      <link>https://dev.to/joodi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joodi"/>
    <language>en</language>
    <item>
      <title>MeetCast: Launch Your Own Webinar Platform in Minutes, Without a VPS</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Sat, 26 Sep 2026 13:48:11 +0000</pubDate>
      <link>https://dev.to/joodi/meetcast-launch-your-own-webinar-platform-in-minutes-without-a-vps-2j5g</link>
      <guid>https://dev.to/joodi/meetcast-launch-your-own-webinar-platform-in-minutes-without-a-vps-2j5g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh38v2jybz090qik4zs66.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh38v2jybz090qik4zs66.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MeetCast&lt;/strong&gt; is a free and fast way to launch your own webinar platform, even without a &lt;strong&gt;VPS&lt;/strong&gt;.&lt;br&gt;
You can also test its features in the &lt;strong&gt;demo version&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To get started, you only need to configure &lt;strong&gt;PostgreSQL&lt;/strong&gt; and &lt;strong&gt;LiveKi&lt;/strong&gt;t in your &lt;strong&gt;ENV&lt;/strong&gt; and deploy the project. For getting started, free services are enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webinar Features:&lt;/strong&gt;&lt;br&gt;
• Create and schedule Webinars and Meetings&lt;br&gt;
• Public and Private Rooms&lt;br&gt;
• Invite Links and Guest Join&lt;br&gt;
• HD Video and Audio&lt;br&gt;
• Screen Sharing&lt;br&gt;
• Participant Grid and speaking status&lt;br&gt;
• Chat, Reactions, and Raise Hand&lt;br&gt;
• Host and Moderator tools&lt;br&gt;
• Mute, Disable Camera, Remove, and Promote/Demote users&lt;br&gt;
• Restrict access to private meetings with Email Allowlist&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform Management:&lt;/strong&gt;&lt;br&gt;
• Admin panel for managing users, meetings, Plans, and orders&lt;br&gt;
• Create different Plans and set limits such as participant capacity and meeting duration&lt;br&gt;
• Manage user access based on their Plan&lt;br&gt;
• Email-based registration and login&lt;br&gt;
• Email Verification and Forgot Password using your own email service&lt;br&gt;
• Billing and Checkout are ready, only payment gateway integration remains&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="http://webinari.ir/" rel="noopener noreferrer"&gt;http://webinari.ir/&lt;/a&gt;&lt;br&gt;
💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://miladjoodi.github.io/#project/meetcast" rel="noopener noreferrer"&gt;https://miladjoodi.github.io/#project/meetcast&lt;/a&gt;&lt;br&gt;
🌐 &lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="https://lnkd.in/ebHU8PsB" rel="noopener noreferrer"&gt;https://lnkd.in/ebHU8PsB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run into any issues while setting up or using MeetCast, feel free to reach out to me by email.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>frontend</category>
      <category>typescript</category>
    </item>
    <item>
      <title>CaptchaKit: A Self-Hosted CAPTCHA Package for React &amp; Next.js + Try It Live</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Fri, 25 Sep 2026 19:13:30 +0000</pubDate>
      <link>https://dev.to/joodi/captchakit-a-self-hosted-captcha-package-for-react-nextjs-try-it-live-23j9</link>
      <guid>https://dev.to/joodi/captchakit-a-self-hosted-captcha-package-for-react-nextjs-try-it-live-23j9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frmmfrsj2exy35xg7s824.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frmmfrsj2exy35xg7s824.jpg" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding CAPTCHA to a React or Next.js app usually means relying on an external service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It supports:&lt;/strong&gt;&lt;br&gt;
&amp;nbsp;• Text, number, math, and image CAPTCHAs&lt;br&gt;
&amp;nbsp;• English and Persian (RTL)&lt;br&gt;
&amp;nbsp;• Easy, medium, and hard difficulty&lt;br&gt;
&amp;nbsp;• Light and dark themes&lt;br&gt;
&amp;nbsp;• Server-side verification&lt;br&gt;
&amp;nbsp;• HMAC-signed tokens&lt;br&gt;
&amp;nbsp;• Expiration, one-time usage, attempt limits, and rate limiting&lt;/p&gt;

&lt;p&gt;The goal was simple: add CAPTCHA protection without adding another external service to your stack.&lt;/p&gt;

&lt;p&gt;The full technical details and setup are available in the documentation.&lt;br&gt;
&amp;nbsp;🔗 &lt;strong&gt;Live demo&lt;/strong&gt;: &lt;a href="https://captchakit.netlify.app/" rel="noopener noreferrer"&gt;https://captchakit.netlify.app/&lt;/a&gt;&lt;br&gt;
&amp;nbsp;📦 &lt;strong&gt;npm&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/captchakit" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/captchakit&lt;/a&gt;&lt;br&gt;
&amp;nbsp;💻 &lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/MiladJoodi/CaptchaKit" rel="noopener noreferrer"&gt;https://github.com/MiladJoodi/CaptchaKit&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>npm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Resend: The easiest way to add email to your app</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Fri, 25 Sep 2026 15:02:46 +0000</pubDate>
      <link>https://dev.to/joodi/resend-the-easiest-way-to-add-email-to-your-app-490m</link>
      <guid>https://dev.to/joodi/resend-the-easiest-way-to-add-email-to-your-app-490m</guid>
      <description>&lt;p&gt;Need to add email to your web app?&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://resend.com/" rel="noopener noreferrer"&gt;Resend&lt;/a&gt; lets you send, receive, track, and manage emails through a simple developer-friendly API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can you do with it?&lt;/strong&gt;&lt;br&gt;
📨 &lt;strong&gt;Transactional emails Verification&lt;/strong&gt;, password reset, invitations, notifications, and more.&lt;/p&gt;

&lt;p&gt;🎨 &lt;strong&gt;React Email&lt;/strong&gt; Build email templates with React and TypeScript instead of dealing with messy email HTML.&lt;/p&gt;

&lt;p&gt;📅 &lt;strong&gt;Scheduling &amp;amp; batch sending Schedule&lt;/strong&gt; emails or send batches through the API.&lt;/p&gt;

&lt;p&gt;📎 &lt;strong&gt;Attachments&lt;/strong&gt; Send files with your emails.&lt;/p&gt;

&lt;p&gt;🔔 &lt;strong&gt;Webhooks&lt;/strong&gt; Receive events for deliveries, bounces, opens, clicks, and other email activity.&lt;/p&gt;

&lt;p&gt;📥** Inbound emails** Receive emails in your application and process their content and attachments.&lt;/p&gt;

&lt;p&gt;👥 &lt;strong&gt;Audiences &amp;amp; broadcasts&lt;/strong&gt; Manage contacts and send email campaigns with analytics.&lt;/p&gt;

&lt;p&gt;📊 &lt;strong&gt;Logs &amp;amp; analytics&lt;/strong&gt; Monitor email activity and troubleshoot delivery issues.&lt;/p&gt;

&lt;p&gt;🔐 &lt;strong&gt;Custom domains&lt;/strong&gt; Send from your own domain with SPF, DKIM, and DMARC authentication.&lt;/p&gt;

&lt;p&gt;🔁 &lt;strong&gt;Idempotency&lt;/strong&gt; Prevent duplicate emails when requests are retried.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;How to set it up&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Create a Resend account Create your account and generate an API key.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add your domain &lt;strong&gt;Add your domain&lt;/strong&gt; in Resend and configure the required DNS records for email authentication.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;3. Add the API key&lt;/strong&gt;&lt;br&gt;
RESEND_API_KEY=re_xxxxxxxxx&lt;br&gt;
Keep it server-side. Never expose the API key in client-side code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Install the SDK&lt;/strong&gt;&lt;br&gt;
npm install resend&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send your first email&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Article content&lt;/strong&gt;&lt;br&gt;
With Next.js, you can call Resend from a Route Handler or Server Action, keeping the API key on the server.&lt;/p&gt;

&lt;p&gt;That's basically it.&lt;/p&gt;

&lt;p&gt;If you're building with Next.js, React, Node.js, or TypeScript, Resend is definitely worth checking out.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>resend</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How I Got a Next.js Project to 100% SEO on Lighthouse</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Tue, 15 Sep 2026 05:21:55 +0000</pubDate>
      <link>https://dev.to/joodi/how-i-got-a-nextjs-project-to-100-seo-on-lighthouse-23ab</link>
      <guid>https://dev.to/joodi/how-i-got-a-nextjs-project-to-100-seo-on-lighthouse-23ab</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6eafvg2osoe20pwivjkz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6eafvg2osoe20pwivjkz.jpg" alt=" " width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently went through the SEO setup of MockData and wanted to see how far I could push the technical side of it.&lt;/p&gt;

&lt;p&gt;The goal wasn't to rank #1 on Google.&lt;/p&gt;

&lt;p&gt;I just wanted to make sure search engines could properly understand and discover the pages I actually want indexed.&lt;/p&gt;

&lt;p&gt;After going through Lighthouse and fixing the issues one by one, MockData reached &lt;strong&gt;100 SEO on Lighthouse&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here are the main things I changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Centralized metadata
&lt;/h3&gt;

&lt;p&gt;One thing that was getting annoying was managing metadata separately across different pages.&lt;/p&gt;

&lt;p&gt;So I created a small helper to keep things consistent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createPageMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;noIndex&lt;/span&gt; &lt;span class="o"&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="nx"&gt;PageMetadata&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;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alternates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;noIndex&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noindex, nofollow&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="s2"&gt;index, follow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now a page can simply define what is different instead of rebuilding all the metadata every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fixed the root layout
&lt;/h3&gt;

&lt;p&gt;I also moved the global defaults into &lt;code&gt;layout.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;metadataBase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;title template&lt;/li&gt;
&lt;li&gt;default description&lt;/li&gt;
&lt;li&gt;Open Graph&lt;/li&gt;
&lt;li&gt;Twitter cards&lt;/li&gt;
&lt;li&gt;robots&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lang&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;metadataBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://mockdata.ir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MockData&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%s | MockData&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also makes relative URLs such as canonical and Open Graph URLs resolve correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Added robots.txt
&lt;/h3&gt;

&lt;p&gt;I added a real &lt;code&gt;robots.ts&lt;/code&gt; instead of leaving crawler rules undefined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;MetadataRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Robots&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="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://mockdata.ir/sitemap.xml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing fancy.&lt;/p&gt;

&lt;p&gt;Just clear rules and a sitemap location.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Added a dynamic sitemap
&lt;/h3&gt;

&lt;p&gt;MockData has more than just a few static pages.&lt;/p&gt;

&lt;p&gt;There are resource pages for things like users, posts, products, and other data.&lt;/p&gt;

&lt;p&gt;So instead of maintaining a huge static XML file manually, I generate the sitemap through Next.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MetadataRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sitemap&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;resources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPublicResources&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://mockdata.ir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lastModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&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="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resource&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="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://mockdata.ir/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lastModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatedAt&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means new public resources can automatically become part of the sitemap.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Added structured data
&lt;/h3&gt;

&lt;p&gt;For pages where it actually makes sense, I added JSON-LD using Schema.org.&lt;/p&gt;

&lt;p&gt;For example, the application itself can be described as a &lt;code&gt;SoftwareApplication&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I also used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WebSite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Organization&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SoftwareApplication&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BreadcrumbList&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part here is not adding as much schema as possible.&lt;/p&gt;

&lt;p&gt;Only add structured data that actually represents the content on the page.&lt;/p&gt;

&lt;p&gt;No fake reviews.&lt;/p&gt;

&lt;p&gt;No fake ratings.&lt;/p&gt;

&lt;p&gt;No made-up information just to make Google happy.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Added breadcrumbs
&lt;/h3&gt;

&lt;p&gt;For nested pages, users can now see a clear hierarchy such as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Home → Docs → Users API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I also represent the same hierarchy in &lt;code&gt;BreadcrumbList&lt;/code&gt; structured data.&lt;/p&gt;

&lt;p&gt;The UI and structured data should describe the same page structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Checked every indexable page
&lt;/h3&gt;

&lt;p&gt;Finally, I went through the public pages individually.&lt;/p&gt;

&lt;p&gt;For each one I checked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is there one clear H1?&lt;/li&gt;
&lt;li&gt;Does the title describe the page?&lt;/li&gt;
&lt;li&gt;Does the description match the actual content?&lt;/li&gt;
&lt;li&gt;Are there useful internal links?&lt;/li&gt;
&lt;li&gt;Should this page really be indexed?&lt;/li&gt;
&lt;li&gt;Is there any empty or useless page exposed to crawlers?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every page needs to be indexed.&lt;/p&gt;

&lt;p&gt;Sometimes &lt;code&gt;noindex&lt;/code&gt; is the correct SEO decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  The result
&lt;/h3&gt;

&lt;p&gt;After fixing these things, I ran Lighthouse again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SEO: 100&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But there's an important distinction here.&lt;/p&gt;

&lt;p&gt;A 100 Lighthouse SEO score does &lt;strong&gt;not&lt;/strong&gt; mean your website will rank first on Google.&lt;/p&gt;

&lt;p&gt;Lighthouse is mostly checking technical SEO basics.&lt;/p&gt;

&lt;p&gt;Actual search rankings depend on much more:&lt;/p&gt;

&lt;p&gt;Content quality, search intent, authority, backlinks, competition, performance, and many other factors.&lt;/p&gt;

&lt;p&gt;For me, the useful part of this process wasn't really the number 100.&lt;/p&gt;

&lt;p&gt;It was making sure MockData has a clean technical foundation before worrying about rankings.&lt;/p&gt;

&lt;p&gt;You can check the project here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mockdata.ir" rel="noopener noreferrer"&gt;https://mockdata.ir&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're building a Next.js app, I'd definitely recommend going through the Lighthouse SEO audit before shipping it.&lt;/p&gt;

&lt;p&gt;It catches a surprising number of small things.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>seo</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Vercel &amp; Netlify Are Great. But What About Deploying Background Workers?</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Sun, 13 Sep 2026 11:25:36 +0000</pubDate>
      <link>https://dev.to/joodi/vercel-netlify-are-great-but-what-about-deploying-background-workers-4onp</link>
      <guid>https://dev.to/joodi/vercel-netlify-are-great-but-what-about-deploying-background-workers-4onp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiyysb2z4mpo5tshtkh65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiyysb2z4mpo5tshtkh65.png" alt=" " width="474" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently tried &lt;strong&gt;&lt;a href="https://railway.app/" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;&lt;/strong&gt; for one of my Next.js projects.&lt;/p&gt;

&lt;p&gt;I needed a &lt;strong&gt;background worker&lt;/strong&gt; to process GitHub data and jobs continuously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vercel&lt;/strong&gt; and &lt;strong&gt;Netlify&lt;/strong&gt; are great for serverless apps, but they're not designed for &lt;strong&gt;long-running worker&lt;/strong&gt; processes.&lt;/p&gt;

&lt;p&gt;Railway makes it simple to run workers, databases, cron jobs, and backend services, while also making environment variables and logs easy to manage.&lt;/p&gt;

&lt;p&gt;It feels like having more control over the backend without having to manage the infrastructure yourself.&lt;/p&gt;

&lt;p&gt;Definitely a tool I'll be using more.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>nextjs</category>
      <category>development</category>
    </item>
    <item>
      <title>No signup. No card. Free GPT &amp; Claude.</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Wed, 26 Aug 2026 08:12:08 +0000</pubDate>
      <link>https://dev.to/joodi/no-signup-no-card-free-gpt-claude-5aek</link>
      <guid>https://dev.to/joodi/no-signup-no-card-free-gpt-claude-5aek</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6xlqy6sebntdyz0u6le0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6xlqy6sebntdyz0u6le0.png" alt=" " width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just go to: &lt;a href="https://Duck.ai" rel="noopener noreferrer"&gt;https://Duck.ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duck.ai&lt;/strong&gt; (by DuckDuckGo ) lets you chat with several AI models for free. Your requests are anonymized, and chats aren’t stored on DuckDuckGo’s servers by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current free models:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPT-5.6 Luna – best for everyday use (default)&lt;/li&gt;
&lt;li&gt;GPT-5.4 mini – solid, but hits limits sooner&lt;/li&gt;
&lt;li&gt;Claude Haiku 4.5&lt;/li&gt;
&lt;li&gt;Mistral Small 4&lt;/li&gt;
&lt;li&gt;gpt-oss-120b&lt;/li&gt;
&lt;li&gt;Gemma 4 31B&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you care about privacy and want quick access to good models without signing up, it’s worth trying.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>chatgpt</category>
      <category>claude</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Your Date Picker Is Outdated. Here’s a Better Way.</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:54:29 +0000</pubDate>
      <link>https://dev.to/joodi/your-date-picker-is-outdated-heres-a-better-way-57h2</link>
      <guid>https://dev.to/joodi/your-date-picker-is-outdated-heres-a-better-way-57h2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F38vwkmlsiwjld6n7n4oi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F38vwkmlsiwjld6n7n4oi.png" alt=" " width="384" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most React apps still use the same old date picker. It works… but it feels clunky, especially on mobile.&lt;/p&gt;

&lt;p&gt;There’s a much better way: an &lt;strong&gt;&lt;a href="https://react-wheel-picker.chanhdai.com/" rel="noopener noreferrer"&gt;iOS-style Wheel Picker&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It scrolls smoothly, has that natural inertia feel, supports infinite looping, and just looks more polished. Users actually enjoy interacting with it. 😊&lt;/p&gt;

&lt;p&gt;One of the best libraries for this right now is &lt;a href="https://www.npmjs.com/package/@ncdai/react-wheel-picker" rel="noopener noreferrer"&gt;@ncdai/react-wheel-picker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It’s:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight and unstyled (so you can fully customize it)&lt;/li&gt;
&lt;li&gt;Smooth on both touch and desktop&lt;/li&gt;
&lt;li&gt;Supports keyboard navigation&lt;/li&gt;
&lt;li&gt;Easy to install with shadcn if you’re using it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Live demo&lt;/strong&gt;: &lt;a href="https://react-wheel-picker.chanhdai.com" rel="noopener noreferrer"&gt;https://react-wheel-picker.chanhdai.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/@ncdai/react-wheel-picker" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@ncdai/react-wheel-picker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/ncdai/react-wheel-picker" rel="noopener noreferrer"&gt;https://github.com/ncdai/react-wheel-picker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install it with:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install @ncdai/react-wheel-picker&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you’re building forms, filters, or any kind of selection UI, give this a try. It’s one of those small upgrades that makes your product feel noticeably better.&lt;/p&gt;

&lt;p&gt;Have you switched to wheel pickers yet? Curious to hear your experience.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Tried Zed for a few days — here’s what actually stood out</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Sun, 09 Aug 2026 10:58:22 +0000</pubDate>
      <link>https://dev.to/joodi/tried-zed-for-a-few-days-heres-what-actually-stood-out-1pei</link>
      <guid>https://dev.to/joodi/tried-zed-for-a-few-days-heres-what-actually-stood-out-1pei</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3buuoizagvunxtlydus4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3buuoizagvunxtlydus4.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://zed.dev/" rel="noopener noreferrer"&gt;Zed&lt;/a&gt;&lt;/strong&gt; is a fast, minimal code editor built in Rust. The same team behind Atom and Tree-sitter made it. It’s designed for speed and working with both humans and AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A few things that stood out:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s really fast. Opening projects and switching files feels almost instant.&lt;/li&gt;
&lt;li&gt;You can run AI agents right inside the editor.&lt;/li&gt;
&lt;li&gt;It has real collaboration features if you’re coding with someone else.&lt;/li&gt;
&lt;li&gt;You can import settings from VS Code or Cursor.&lt;/li&gt;
&lt;li&gt;On the free plan you can still connect your own models. I used OpenRouter and it worked fine.&lt;/li&gt;
&lt;li&gt;You can try Pro for 14 days without adding a credit card.&lt;/li&gt;
&lt;li&gt;They actually collaborated with Anthropic early on when building the AI features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;One small tip&lt;/strong&gt;: the folder panel is on the right by default. If you prefer it on the left like VS Code, you can move it. Guide is here:&lt;br&gt;
&lt;a href="https://zed.dev/blog/new-panel-system" rel="noopener noreferrer"&gt;https://zed.dev/blog/new-panel-system&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overall it feels clean and light. If you’re looking for something faster and simpler than the usual options, it’s worth a try.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>frontend</category>
      <category>backend</category>
      <category>software</category>
    </item>
    <item>
      <title>🥈 React Performance Tips: 12 Ways to Make Your App Faster</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Wed, 05 Aug 2026 20:00:30 +0000</pubDate>
      <link>https://dev.to/joodi/react-performance-tips-12-ways-to-make-your-app-faster-5bop</link>
      <guid>https://dev.to/joodi/react-performance-tips-12-ways-to-make-your-app-faster-5bop</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90fdof3fpdoyyadphdx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90fdof3fpdoyyadphdx4.png" alt=" " width="799" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React is fast by default.&lt;/p&gt;

&lt;p&gt;But as an application grows, unnecessary renders, large lists, too much JavaScript, and excessive API requests can make it slower.&lt;/p&gt;

&lt;p&gt;The good news is that you don't need complicated tricks everywhere.&lt;/p&gt;

&lt;p&gt;Let's look at 12 practical ways to improve React performance, from simple improvements to more advanced techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Stop Rendering What You Don't Need
&lt;/h2&gt;

&lt;p&gt;Every time a component renders, React runs its component function again.&lt;/p&gt;

&lt;p&gt;That doesn't mean every render is a problem. The problem is doing expensive work when nothing actually changed.&lt;/p&gt;

&lt;p&gt;For example, avoid putting unrelated state in a component that contains a large part of your UI.&lt;/p&gt;

&lt;p&gt;Instead, keep components focused so an update only affects the part of the UI that actually needs it.&lt;/p&gt;

&lt;p&gt;The goal isn't to prevent every render.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal is to avoid unnecessary work.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Keep Your State in the Right Place
&lt;/h2&gt;

&lt;p&gt;Don't move every piece of state to the top of your application.&lt;/p&gt;

&lt;p&gt;If only one component needs the state, keep it there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchBox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&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;input&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onChange&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping state close to where it is used can reduce unnecessary updates in other parts of the application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep state as close as possible to the components that use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Don't Store Data You Can Calculate
&lt;/h2&gt;

&lt;p&gt;Not everything needs &lt;code&gt;useState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, don't store &lt;code&gt;fullName&lt;/code&gt; separately if you already have &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Avoid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFullName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setFullName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just calculate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids unnecessary state and an unnecessary Effect.&lt;/p&gt;

&lt;p&gt;A simple rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can calculate it during render, you probably don't need state for it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Make Large Lists Faster
&lt;/h2&gt;

&lt;p&gt;Rendering thousands of elements can become expensive.&lt;/p&gt;

&lt;p&gt;Imagine a chat application with 10,000 messages.&lt;/p&gt;

&lt;p&gt;You don't need all 10,000 messages in the DOM at the same time.&lt;/p&gt;

&lt;p&gt;For large lists, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Virtualization&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;li&gt;Infinite scrolling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Virtualization keeps only the visible items, plus a small buffer, mounted in the DOM.&lt;/p&gt;

&lt;p&gt;Libraries such as &lt;code&gt;react-window&lt;/code&gt; can help with this.&lt;/p&gt;

&lt;p&gt;Don't add virtualization to every list. A list with 50 items probably doesn't need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Load Heavy Components Only When Needed
&lt;/h2&gt;

&lt;p&gt;Your users shouldn't have to download code they don't need immediately.&lt;/p&gt;

&lt;p&gt;React supports lazy loading with &lt;code&gt;lazy&lt;/code&gt; and &lt;code&gt;Suspense&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the Settings component can be loaded when it is needed instead of being included in the initial JavaScript.&lt;/p&gt;

&lt;p&gt;This is useful for heavy or rarely visited features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Charts&lt;/li&gt;
&lt;li&gt;Editors&lt;/li&gt;
&lt;li&gt;Maps&lt;/li&gt;
&lt;li&gt;Settings pages&lt;/li&gt;
&lt;li&gt;Large dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Smaller initial bundles usually mean faster initial loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Keep Search and UI Interactions Responsive
&lt;/h2&gt;

&lt;p&gt;Some updates don't need to happen immediately.&lt;/p&gt;

&lt;p&gt;For example, a search input should respond instantly while filtering thousands of results can happen at a lower priority.&lt;/p&gt;

&lt;p&gt;React provides &lt;code&gt;useTransition&lt;/code&gt; and &lt;code&gt;useDeferredValue&lt;/code&gt; for these situations.&lt;/p&gt;

&lt;p&gt;You can also debounce user input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDebounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of sending a request on every keystroke, you can wait until the user stops typing.&lt;/p&gt;

&lt;p&gt;These techniques are useful for search, filtering, large lists, and complex dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Avoid Unnecessary API Requests
&lt;/h2&gt;

&lt;p&gt;Performance isn't only about rendering.&lt;/p&gt;

&lt;p&gt;Too many network requests can also make your application feel slow.&lt;/p&gt;

&lt;p&gt;Depending on your application, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching responses&lt;/li&gt;
&lt;li&gt;Request deduplication&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;li&gt;Debouncing search&lt;/li&gt;
&lt;li&gt;Canceling outdated requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if a user quickly searches for:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;you don't necessarily want three requests running at the same time.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't make the network do work you don't need.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Memoization: When Should You Actually Use It?
&lt;/h2&gt;

&lt;p&gt;React provides three common memoization tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useMemo&lt;/code&gt; caches a calculation result.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useCallback&lt;/code&gt; caches a function reference.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;React.memo&lt;/code&gt; can skip a component render when its props haven't changed.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&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="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But don't add memoization everywhere.&lt;/p&gt;

&lt;p&gt;Memoization also has a cost and adds complexity.&lt;/p&gt;

&lt;p&gt;Use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A calculation is expensive.&lt;/li&gt;
&lt;li&gt;A component renders unnecessarily.&lt;/li&gt;
&lt;li&gt;A stable reference is actually useful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don't optimize code that doesn't have a performance problem.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. React Compiler: Less Manual Optimization
&lt;/h2&gt;

&lt;p&gt;Modern React introduces another important piece: &lt;strong&gt;React Compiler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Compiler can automatically optimize components, values, and functions in many cases, reducing the need for manual memoization.&lt;/p&gt;

&lt;p&gt;That means you shouldn't automatically think:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;whenever you see a performance problem.&lt;/p&gt;

&lt;p&gt;First ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is there actually a performance problem?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If React Compiler is enabled for your project, let it handle the optimizations it can, and use manual memoization when you have a specific reason to do so.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Use Stable Keys and References
&lt;/h2&gt;

&lt;p&gt;Keys help React identify items in a list.&lt;/p&gt;

&lt;p&gt;Prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stable keys help React understand which item was added, removed, or changed.&lt;/p&gt;

&lt;p&gt;The same idea applies to object and function references.&lt;/p&gt;

&lt;p&gt;Creating new objects or functions on every render can matter when you're working with memoized components.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Find the Real Bottleneck
&lt;/h2&gt;

&lt;p&gt;Once you understand the common optimization techniques, don't guess.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;React DevTools Profiler&lt;/strong&gt; to see which components render and how much time they take.&lt;/p&gt;

&lt;p&gt;You can also use the browser's Performance panel to investigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long tasks&lt;/li&gt;
&lt;li&gt;Slow scripting&lt;/li&gt;
&lt;li&gt;Layout work&lt;/li&gt;
&lt;li&gt;Rendering problems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This component feels slow."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Find out &lt;strong&gt;why&lt;/strong&gt; it is slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Measure Again Before You Ship
&lt;/h2&gt;

&lt;p&gt;After making an optimization, measure the result again.&lt;/p&gt;

&lt;p&gt;Did the render time improve?&lt;/p&gt;

&lt;p&gt;Did the bundle become smaller?&lt;/p&gt;

&lt;p&gt;Did the interaction become more responsive?&lt;/p&gt;

&lt;p&gt;If the change doesn't improve anything, you may not need it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance Checklist
&lt;/h3&gt;

&lt;p&gt;Before shipping your React application, ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Am I rendering unnecessary UI?&lt;/li&gt;
&lt;li&gt;Is my state in the right place?&lt;/li&gt;
&lt;li&gt;Am I storing values I can calculate?&lt;/li&gt;
&lt;li&gt;Are large lists handled efficiently?&lt;/li&gt;
&lt;li&gt;Am I loading heavy code only when needed?&lt;/li&gt;
&lt;li&gt;Are search and interactions responsive?&lt;/li&gt;
&lt;li&gt;Am I making unnecessary API requests?&lt;/li&gt;
&lt;li&gt;Am I using memoization for a real reason?&lt;/li&gt;
&lt;li&gt;Can React Compiler handle the optimization?&lt;/li&gt;
&lt;li&gt;Am I using stable keys?&lt;/li&gt;
&lt;li&gt;Did I measure the actual bottleneck?&lt;/li&gt;
&lt;li&gt;Did I verify the improvement afterward?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best React optimization isn't adding more code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's making React do less unnecessary work.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>frontend</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🚀 Next.js 16.3 Has a New useOffline Hook</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Tue, 04 Aug 2026 12:54:35 +0000</pubDate>
      <link>https://dev.to/joodi/nextjs-163-has-a-new-useoffline-hook-3dfj</link>
      <guid>https://dev.to/joodi/nextjs-163-has-a-new-useoffline-hook-3dfj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1zj2cos77gdgfoynogm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1zj2cos77gdgfoynogm.png" alt=" " width="328" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meet &lt;code&gt;useOffline&lt;/code&gt; 👇&lt;/p&gt;

&lt;p&gt;It lets you know when the user loses their internet connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isOffline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useOffline&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;isOffline&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 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="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So instead of your app silently breaking when the connection drops, you can show a proper offline state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example:&lt;/strong&gt;&lt;br&gt;
📡 &lt;strong&gt;Online&lt;/strong&gt;→ Show the app&lt;br&gt;
📴 &lt;strong&gt;Offline&lt;/strong&gt;→ Show an offline message or disable actions that need the network&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;One important thing:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useOffline&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; make your app offline-first.&lt;/p&gt;

&lt;p&gt;You still need things like caching, IndexedDB, and sync logic if you want the app to actually work offline.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;code&gt;useOffline&lt;/code&gt; is currently experimental, so its API may change.&lt;/p&gt;

&lt;p&gt;📚 Docs: &lt;a href="https://nextjs.org/docs/app/api-reference/functions/use-offline" rel="noopener noreferrer"&gt;Next.js Documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>No More nodemon or dotenv? Node.js Can Handle It Now</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Sun, 02 Aug 2026 20:00:02 +0000</pubDate>
      <link>https://dev.to/joodi/no-more-nodemon-or-dotenv-nodejs-can-handle-it-now-2inb</link>
      <guid>https://dev.to/joodi/no-more-nodemon-or-dotenv-nodejs-can-handle-it-now-2inb</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgll5xybjuafzx5m7ukhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgll5xybjuafzx5m7ukhz.png" alt=" " width="799" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might not need two popular packages in your &lt;strong&gt;Node.js&lt;/strong&gt; projects anymore.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since Node.js 20.6, Node can load .env files natively with --env-file.&lt;/li&gt;
&lt;li&gt;And since Node.js 22, --watch is stable for automatic restarts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --env-file=.env --watch app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;No dotenv.&lt;/li&gt;
&lt;li&gt;No nodemon.&lt;/li&gt;
&lt;li&gt;No extra setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a simple Node.js app, the runtime can now handle both.&lt;br&gt;
Of course, nodemon and dotenv still make sense if you need their extra features.&lt;/p&gt;

&lt;p&gt;📌 Official Node.js docs: &lt;a href="https://nodejs.org/docs/latest/api/cli.html?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Node.js CLI documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>backend</category>
      <category>frontend</category>
    </item>
    <item>
      <title>If Claude Code is expensive or hard to access for you, try OpenCode</title>
      <dc:creator>Joodi</dc:creator>
      <pubDate>Thu, 30 Jul 2026 09:56:02 +0000</pubDate>
      <link>https://dev.to/joodi/if-claude-code-is-expensive-or-hard-to-access-for-you-try-opencode-5hfj</link>
      <guid>https://dev.to/joodi/if-claude-code-is-expensive-or-hard-to-access-for-you-try-opencode-5hfj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsbbsyk1lmbga177827gp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsbbsyk1lmbga177827gp.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If &lt;strong&gt;Claude Code&lt;/strong&gt; is expensive or hard to access for you, try &lt;strong&gt;OpenCode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s an open-source AI coding agent that works in the terminal, desktop, and as a VS Code extension.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free models available:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DeepSeek V4 Flash Free (best option)&lt;/li&gt;
&lt;li&gt;MiMo v2.5 Free&lt;/li&gt;
&lt;li&gt;Nemotron 3 Ultra Free&lt;/li&gt;
&lt;li&gt;North Mini Code Free&lt;/li&gt;
&lt;li&gt;Big Pickle&lt;/li&gt;
&lt;li&gt;Ling-3.0-flash Free&lt;/li&gt;
&lt;li&gt;Laguna S 2.1 Free&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These free models work well for most daily coding tasks. Note: They have daily usage limits (they reset every day).&lt;/p&gt;

&lt;p&gt;How to install (Windows):&lt;br&gt;
First, make sure Node.js is installed on your system.&lt;/p&gt;

&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; opencode-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installation, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You can also install the &lt;strong&gt;VS Code extension&lt;/strong&gt; for a smoother experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There's also a desktop app. You can open your project directly in it and use the AI agent without relying on VS Code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Like Claude Code, it guides you through actions by presenting options and asking for confirmation before executing them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenCode lets you use free models or connect any API key you want. It’s flexible, open-source, and a solid alternative to Claude Code.&lt;/p&gt;

&lt;p&gt;I tested it myself. Setup is easy and the free models are usable for real work.&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://opencode.ai/" rel="noopener noreferrer"&gt;https://opencode.ai/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>frontend</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
