<?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: Israel Michael</title>
    <description>The latest articles on Forem by Israel Michael (@mikelisrael).</description>
    <link>https://forem.com/mikelisrael</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%2F1916107%2F28a62a98-2e6c-460f-9376-11fb1b967710.png</url>
      <title>Forem: Israel Michael</title>
      <link>https://forem.com/mikelisrael</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mikelisrael"/>
    <language>en</language>
    <item>
      <title>React vs Next.js vs TanStack Start: Deciding on the Right Tool</title>
      <dc:creator>Israel Michael</dc:creator>
      <pubDate>Sun, 08 Feb 2026 16:32:51 +0000</pubDate>
      <link>https://forem.com/mikelisrael/react-vs-nextjs-vs-tanstack-start-deciding-on-the-right-tool-lib</link>
      <guid>https://forem.com/mikelisrael/react-vs-nextjs-vs-tanstack-start-deciding-on-the-right-tool-lib</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.amazonaws.com%2Fuploads%2Farticles%2F0pxo7ifpx74bu2jwzxc9.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.amazonaws.com%2Fuploads%2Farticles%2F0pxo7ifpx74bu2jwzxc9.jpg" alt="what tool is better to use for frontend development" width="800" height="1195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  React vs Next.js vs TanStack Start: Deciding on the Right Tool
&lt;/h2&gt;

&lt;p&gt;Choosing the right tool for a frontend project is more than just picking something familiar. React, Next.js, and the new TanStack Start framework each solve similar problems in different ways, and understanding their design goals can help you make the best choice for your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  React: The Core UI Library
&lt;/h3&gt;

&lt;p&gt;React is the foundational UI library for building interactive interfaces. It doesn’t come with routing, data fetching, or server rendering by default, but it gives you the pure building blocks — components, state, hooks, and rendering. React is flexible, battle-tested, and supported by a massive ecosystem of tools and libraries.&lt;/p&gt;

&lt;p&gt;When to use React alone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app is heavily interactive, and you don’t need server rendering.&lt;/li&gt;
&lt;li&gt;You want total control over your stack and are comfortable choosing your own routing and data libraries.&lt;/li&gt;
&lt;li&gt;You’re building dashboards, internal tools, or SPAs where SEO isn’t a priority.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React is essentially the baseline for everything that follows here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js: The Production Ready Framework
&lt;/h3&gt;

&lt;p&gt;Next.js is built on top of React and adds routing, server rendering, static site generation, and automatic optimizations. It’s ideal for production applications where performance and SEO matter.&lt;/p&gt;

&lt;p&gt;Next.js supports features like SSR, SSG, and incremental static regeneration out of the box, and its App Router makes server components the default. This can simplify building content-rich sites, but it also brings complexity and conventions you have to learn.&lt;/p&gt;

&lt;p&gt;Strengths of Next.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excellent SEO and performance with server rendering&lt;/li&gt;
&lt;li&gt;Built-in file-based routing and tooling that gets you shipping quickly&lt;/li&gt;
&lt;li&gt;Mature ecosystem and widespread adoption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic caching and server component behavior can feel opaque to debug&lt;/li&gt;
&lt;li&gt;It has heavier defaults and tight integration with the Vercel platform, though it can be deployed elsewhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next.js remains the established choice for content sites, e-commerce platforms, and applications where SEO or SSR is critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  TanStack Start: A New Framework with Strong Dev Ergonomics
&lt;/h3&gt;

&lt;p&gt;TanStack Start is a new full-stack React framework powered by TanStack Router and Vite. It aims to unify modern frontend needs with clearer control and a simpler mental model than larger frameworks, while still offering SSR, streaming, server functions, and deployment flexibility.&lt;/p&gt;

&lt;p&gt;TanStack Start takes a different approach than Next.js. It uses traditional client-side React components that are server-rendered by default, giving you SSR benefits with full client-side interactivity. Server Components are planned but not yet supported.&lt;/p&gt;

&lt;p&gt;TanStack Start is currently in release candidate and near v1, meaning it’s feature-complete and considered production-ready by many early adopters for real projects, even though it hasn’t reached a stable v1 release yet.&lt;/p&gt;

&lt;p&gt;Strengths of TanStack Start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deep TypeScript support and type-safe routing&lt;/li&gt;
&lt;li&gt;SSR and streaming through explicit primitives&lt;/li&gt;
&lt;li&gt;Flexible deployment anywhere JavaScript runs&lt;/li&gt;
&lt;li&gt;Developer experience powered by Vite with fast startup and HMR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Still newer than Next.js with a smaller ecosystem&lt;/li&gt;
&lt;li&gt;Doesn’t support React Server Components yet, though integration is planned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many developers report that Start feels closer to the React way of thinking, without as much framework magic, which leads to predictable behavior and easier debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which One Should You Choose?
&lt;/h3&gt;

&lt;p&gt;React alone is a great core library for flexible UI work and complex SPAs.&lt;br&gt;
Next.js shines when you need SEO, SSR, and a mature framework with established conventions.&lt;br&gt;
TanStack Start is a promising alternative when you want performance, type safety, explicit control, and flexibility without the implicit complexity of larger frameworks.&lt;/p&gt;

&lt;p&gt;These tools are not mutually exclusive. For example, you can use TanStack libraries like TanStack Query and Router within Next.js. Understanding the philosophy and current landscape helps you choose with confidence.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
      <category>programming</category>
    </item>
    <item>
      <title>Mastering the art of frontend performance optimization</title>
      <dc:creator>Israel Michael</dc:creator>
      <pubDate>Sun, 08 Feb 2026 15:48:56 +0000</pubDate>
      <link>https://forem.com/mikelisrael/mastering-the-art-of-frontend-performance-optimization-284b</link>
      <guid>https://forem.com/mikelisrael/mastering-the-art-of-frontend-performance-optimization-284b</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.amazonaws.com%2Fuploads%2Farticles%2Fd64wx72qemwy7iavz8hw.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%2Fd64wx72qemwy7iavz8hw.png" alt=" " width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a Frontend Software Engineer, I’ve worked on a range of challenging projects, and one area I focus on constantly is frontend performance. Why? Because a fast, responsive application directly improves user experience, retention, and overall satisfaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Don’t Ignore Performance Issues&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s easy to overlook slow load times or laggy interfaces, but ignoring them is not just lazy programming—it can drive users away and hurt your product’s reputation. A smooth, efficient user experience is our responsibility as developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Performance Matters&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User experience:&lt;/strong&gt; Fast websites keep users happy; slow pages frustrate them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO benefits:&lt;/strong&gt; Search engines favor speed, boosting your site’s ranking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversion rates:&lt;/strong&gt; Quicker, responsive sites encourage users to stay and engage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Effective Strategies I’ve Used&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Refactoring:&lt;/strong&gt; Optimizing and cleaning up code improves load times and maintainability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive design:&lt;/strong&gt; Using React and Next.js, I ensure applications work seamlessly across desktops, tablets, and smartphones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced analytics:&lt;/strong&gt; Tracking user interactions helps identify performance bottlenecks and improve UX based on real feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security measures:&lt;/strong&gt; Secure APIs and strong authentication are essential for reliable, safe applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A Call to Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s take pride in our work and prioritize performance from the start. Fast, reliable applications are not just a technical goal—they shape the user’s experience and trust.&lt;/p&gt;

&lt;p&gt;What are your go-to strategies for frontend performance optimization? Have you faced challenges in this area? Let’s share experiences and learn from each other.&lt;/p&gt;

&lt;p&gt;Reach out if you’d like to discuss frontend development, ask questions, or collaborate on exciting projects. Stay curious and keep coding! 💻✨&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
      <category>performance</category>
    </item>
    <item>
      <title>The Principles of Good Design</title>
      <dc:creator>Israel Michael</dc:creator>
      <pubDate>Sun, 08 Feb 2026 15:35:04 +0000</pubDate>
      <link>https://forem.com/mikelisrael/the-principles-of-good-design-321h</link>
      <guid>https://forem.com/mikelisrael/the-principles-of-good-design-321h</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.amazonaws.com%2Fuploads%2Farticles%2Folp3davkewpund3uz6lg.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%2Folp3davkewpund3uz6lg.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve all experienced it—scrolling through social media and stopping at a design that just grabs your attention. It looks polished, engaging, and effortless. Then there are those designs that feel… off. They lack cohesion, confuse the viewer, or just don’t resonate.&lt;/p&gt;

&lt;p&gt;Good design isn’t magic, but it can feel like it. A well-crafted graphic or interface can inform, entertain, and evoke emotion. The secret is understanding a few core principles that make design work.&lt;/p&gt;

&lt;p&gt;Here are four key principles to level up your designs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Contrast&lt;/strong&gt;&lt;br&gt;
Contrast adds visual interest by using opposing elements such as light and dark, big and small, or bold and subtle. Without it, a design feels flat and unengaging. Contrast helps guide the viewer’s eye through the composition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Balance&lt;/strong&gt;&lt;br&gt;
Balance makes a design feel stable and harmonious. This doesn’t always mean symmetry. By distributing visual weight thoughtfully, you create a sense of order and cohesiveness that feels natural to the viewer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Hierarchy&lt;/strong&gt;&lt;br&gt;
Not all information is equally important. Hierarchy uses size, colour, and placement to prioritize elements, guiding attention to the most crucial parts first. It ensures your message is clear and easily digestible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Simplicity&lt;/strong&gt;&lt;br&gt;
Simplicity focuses on what matters most and removes distractions. A clean design communicates effectively and leaves a stronger impression. As Steve Jobs said, achieving simplicity requires effort, but the result allows your work to move mountains.&lt;/p&gt;

&lt;p&gt;Mastering these principles allows you to create designs that captivate, inform, and leave a lasting impression.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>design</category>
      <category>ui</category>
      <category>ux</category>
    </item>
    <item>
      <title>Syncing Data Across Browser Tabs in Next.js: A Frontend 'Cron Job' Solution for Timed Fetching</title>
      <dc:creator>Israel Michael</dc:creator>
      <pubDate>Sun, 08 Feb 2026 15:26:54 +0000</pubDate>
      <link>https://forem.com/mikelisrael/syncing-data-across-browsers-in-nextjs-a-frontend-cron-job-solution-for-timed-fetching-18m2</link>
      <guid>https://forem.com/mikelisrael/syncing-data-across-browsers-in-nextjs-a-frontend-cron-job-solution-for-timed-fetching-18m2</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.amazonaws.com%2Fuploads%2Farticles%2Fyynf1c3kgresbducpfx6.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%2Fyynf1c3kgresbducpfx6.png" alt=" " width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine this. You are building a dynamic Next.js app where data needs to refresh every two minutes. Sounds simple. Drop a setInterval inside useEffect and move on.&lt;/p&gt;

&lt;p&gt;That was my assumption too, until I opened multiple browser tabs.&lt;/p&gt;

&lt;p&gt;Each tab was fetching data on its own schedule. Nothing was aligned. One tab refreshed, another lagged behind, and the experience felt messy. That was not acceptable.&lt;/p&gt;

&lt;p&gt;This post documents how I solved that problem by building a frontend “cron job” that synchronizes data fetching across all open tabs. I will walk through the initial approach, the issue it caused, and the solution that finally made everything click.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting out: the timer-based approach
&lt;/h3&gt;

&lt;p&gt;I began with a straightforward setup. Fetch on mount, then fetch every two minutes.&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&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="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="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="s2"&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;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;Page&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&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="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;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;response&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/getData&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;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&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;fetchData&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;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120000&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="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this works perfectly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem: tabs falling out of sync
&lt;/h3&gt;

&lt;p&gt;The issue appeared as soon as I opened a second tab.&lt;/p&gt;

&lt;p&gt;Each tab runs its own instance of setInterval, which means timing depends on when the tab was opened.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Open tab A at 12:01. It fetches at 12:03, 12:05, and so on.&lt;/li&gt;
&lt;li&gt;Open tab B at 12:02. It fetches at 12:04, 12:06, and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same app, same user, different data states. That inconsistency was the real problem.&lt;/p&gt;

&lt;p&gt;What I actually needed was this:&lt;/p&gt;

&lt;p&gt;All tabs should fetch at the same exact moments. Ideally at fixed two minute boundaries like 12:00, 12:02, 12:04, no matter when the tab was opened.&lt;/p&gt;

&lt;h3&gt;
  
  
  The idea: align all fetches to real time
&lt;/h3&gt;

&lt;p&gt;Instead of starting a timer immediately, I decided to align fetching to the clock.&lt;/p&gt;

&lt;p&gt;The plan was simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculate how long until the next even two minute mark.&lt;/li&gt;
&lt;li&gt;Wait until that moment using setTimeout.&lt;/li&gt;
&lt;li&gt;From there, run a steady two minute interval using setInterval.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This way, every tab locks onto the same schedule.&lt;/p&gt;

&lt;h3&gt;
  
  
  The final implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&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="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="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&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="s2"&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;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;Page&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Fetch function wrapped in useCallback to prevent unnecessary re-renders&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;try&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;response&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/getData&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;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error fetching data:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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="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="c1"&gt;// Fetch immediately on mount so users don't wait up to 2 minutes&lt;/span&gt;
    &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Get current time&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// Calculate milliseconds until the next even 2-minute mark (12:00, 12:02, 12:04, etc.)&lt;/span&gt;
    &lt;span class="c1"&gt;// Formula: 120000ms (2 min) - (current position within 2-min cycle)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;millisecondsUntilNextEvenMinute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="mi"&gt;120000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; 
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMinutes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="c1"&gt;// Minutes component&lt;/span&gt;
       &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSeconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;          &lt;span class="c1"&gt;// Seconds component&lt;/span&gt;
       &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMilliseconds&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;            &lt;span class="c1"&gt;// Milliseconds component for precision&lt;/span&gt;

    &lt;span class="c1"&gt;// Variable to store the interval ID so we can clear it on cleanup&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;intervalId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Wait until the next even 2-minute boundary&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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="c1"&gt;// Fetch at the exact 2-minute mark&lt;/span&gt;
      &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Now that we're synced, fetch every 2 minutes going forward&lt;/span&gt;
      &lt;span class="nx"&gt;intervalId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;millisecondsUntilNextEvenMinute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Cleanup function: clear both timeout and interval to prevent memory leaks&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="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intervalId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intervalId&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;fetchData&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Include fetchData in dependencies&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is happening here
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initial delay calculation&lt;/strong&gt;&lt;br&gt;
I calculate how many milliseconds remain until the next even two minute mark.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delayed first fetch&lt;/strong&gt;&lt;br&gt;
setTimeout ensures the first fetch happens exactly on that boundary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stable interval after sync&lt;/strong&gt;&lt;br&gt;
Once aligned, setInterval keeps all tabs fetching together every two minutes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now every tab behaves the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a tab at 12:01:29. It waits until 12:02:00, then fetches every two minutes.&lt;/li&gt;
&lt;li&gt;Open another tab at 12:01:58. It waits two seconds, then fetches at 12:02:00 alongside the first tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect sync, every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;This change looks small, but it dramatically improved consistency across tabs. The pattern behaves like a frontend cron job, anchored to real time rather than tab lifecycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  When this approach makes sense
&lt;/h3&gt;

&lt;p&gt;This is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data needs to stay consistent across multiple open tabs.&lt;/li&gt;
&lt;li&gt;Timing matters more than “fetch every X minutes from mount”.&lt;/li&gt;
&lt;li&gt;A plain setInterval introduces drift you cannot afford.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes the difference between working code and reliable code is simply aligning with time instead of starting from zero.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Is "use client" Bad for SEO?</title>
      <dc:creator>Israel Michael</dc:creator>
      <pubDate>Sun, 08 Feb 2026 15:18:35 +0000</pubDate>
      <link>https://forem.com/mikelisrael/is-use-client-bad-for-seo-10gp</link>
      <guid>https://forem.com/mikelisrael/is-use-client-bad-for-seo-10gp</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.amazonaws.com%2Fuploads%2Farticles%2Fu89ldn7cm64xatk3fhnp.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%2Fu89ldn7cm64xatk3fhnp.png" alt="Use client on white background" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've been working with Next.js lately, you've probably seen the &lt;code&gt;use client&lt;/code&gt; directive pop up in components. It's just one line at the top of a file, but it raises an important question: does it affect SEO?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short answer: No.&lt;/strong&gt; Client components don't hurt SEO. Let me explain why.&lt;/p&gt;

&lt;h2&gt;
  
  
  What use client actually does
&lt;/h2&gt;

&lt;p&gt;In Next.js 13 and above, components are server components by default. When you add &lt;code&gt;use client&lt;/code&gt; to a component, you're telling Next.js this component needs client-side features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State (useState, useEffect)&lt;/li&gt;
&lt;li&gt;Event handlers&lt;/li&gt;
&lt;li&gt;Browser-only APIs (like window or localStorage)&lt;/li&gt;
&lt;li&gt;Animations or heavy interactivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Here's the key thing:&lt;/strong&gt; Client components are still pre-rendered on the server and included in the initial HTML. Search engines see them immediately, exactly the same as server components.&lt;/p&gt;

&lt;p&gt;The difference is that client components are also bundled and sent to the browser for hydration—making them interactive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why people think use client hurts SEO (and why they're wrong)
&lt;/h2&gt;

&lt;p&gt;There's a common misconception that client components aren't server-rendered. This isn't true.&lt;/p&gt;

&lt;p&gt;Both server components and client components appear in the initial HTML that gets sent to the browser. From a crawler's perspective, there's no difference. Google sees the content immediately either way.&lt;/p&gt;

&lt;p&gt;So putting an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, product description, or blog content in a client component is totally fine for SEO. The content is there in the HTML from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually matters for SEO
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;use client&lt;/code&gt; itself doesn't hurt SEO, there are two things that DO matter:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Don't hide content behind interactivity
&lt;/h3&gt;

&lt;p&gt;This is the real SEO risk. If content only appears after a user clicks a button, opens a tab, or submits a form, crawlers won't see it.&lt;/p&gt;

&lt;p&gt;Crawlers load the page and run JavaScript, but they don't interact with it. They don't click buttons or switch tabs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad for SEO:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product details hidden behind a "Read More" button&lt;/li&gt;
&lt;li&gt;Pricing shown only after selecting a tab&lt;/li&gt;
&lt;li&gt;Content that requires form submission to view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fine for SEO:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactive components that render content immediately&lt;/li&gt;
&lt;li&gt;Client components with state that shows content on load&lt;/li&gt;
&lt;li&gt;Animations that don't hide initial content&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Be mindful of performance
&lt;/h3&gt;

&lt;p&gt;Client components increase your JavaScript bundle size. If you're overusing &lt;code&gt;use client&lt;/code&gt; across your entire app, you can end up with a bloated bundle that slows down your site.&lt;/p&gt;

&lt;p&gt;Performance affects SEO indirectly through Core Web Vitals and page speed rankings. But this is a holistic concern about your app's architecture, not a per-component decision.&lt;/p&gt;

&lt;p&gt;You shouldn't avoid putting an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; in a client component just because it's an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;. If that component needs interactivity, use &lt;code&gt;use client&lt;/code&gt;. The performance cost comes from the component being in the bundle, not from what content it contains.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual decision tree
&lt;/h2&gt;

&lt;p&gt;When deciding between server and client components, ask yourself:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this component need client-side features?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State management?&lt;/li&gt;
&lt;li&gt;Event handlers?&lt;/li&gt;
&lt;li&gt;Browser APIs?&lt;/li&gt;
&lt;li&gt;Interactivity after page load?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Yes?&lt;/strong&gt; → Use &lt;code&gt;use client&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;No?&lt;/strong&gt; → Keep it as a server component&lt;/p&gt;

&lt;p&gt;That's it. It's about functionality, not SEO.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use use client correctly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DO use &lt;code&gt;use client&lt;/code&gt; for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forms with validation&lt;/li&gt;
&lt;li&gt;Interactive widgets&lt;/li&gt;
&lt;li&gt;Modals and dialogs&lt;/li&gt;
&lt;li&gt;Tabs (as long as content is visible on initial render)&lt;/li&gt;
&lt;li&gt;Animations&lt;/li&gt;
&lt;li&gt;Any component that needs state or browser APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DON'T worry about:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether the component contains an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; or important text&lt;/li&gt;
&lt;li&gt;Search engine indexing—crawlers see client components just fine&lt;/li&gt;
&lt;li&gt;Per-component performance decisions based on content type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DO worry about:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hiding content behind clicks, tabs, or interactions&lt;/li&gt;
&lt;li&gt;Overall bundle size if you're using &lt;code&gt;use client&lt;/code&gt; everywhere&lt;/li&gt;
&lt;li&gt;Whether you actually need client features or just defaulted to &lt;code&gt;use client&lt;/code&gt; out of habit&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;use client&lt;/code&gt; doesn't hurt SEO. Both client and server components appear in the initial HTML that crawlers see.&lt;/p&gt;

&lt;p&gt;The choice between them should be based on whether you need client-side features, not whether the content is important for SEO.&lt;/p&gt;

&lt;p&gt;The real SEO concerns are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hiding content behind interactivity&lt;/strong&gt; that requires user action&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overall app performance&lt;/strong&gt; from excessive JavaScript bundles&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Get those right, and you can use client components wherever you need them without worrying about SEO.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; An earlier version of this post incorrectly stated that client components aren't server-rendered and recommended against putting SEO-important content in them. That was wrong. Thanks to the Vercel and Next.js team for the corrections.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>performance</category>
    </item>
    <item>
      <title>Stop Using Redux for Request-Response Management – It’s Making Your Life Harder</title>
      <dc:creator>Israel Michael</dc:creator>
      <pubDate>Sun, 08 Feb 2026 15:11:35 +0000</pubDate>
      <link>https://forem.com/mikelisrael/stop-using-redux-for-request-response-management-its-making-your-life-harder-18a0</link>
      <guid>https://forem.com/mikelisrael/stop-using-redux-for-request-response-management-its-making-your-life-harder-18a0</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.amazonaws.com%2Fuploads%2Farticles%2F6itsejhsind520qpgsq8.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%2F6itsejhsind520qpgsq8.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me be blunt: if you’re still using Redux to manage API requests, you’re making your life harder than it needs to be.&lt;/p&gt;

&lt;p&gt;Redux has had a legendary run. For years, it was &lt;em&gt;the&lt;/em&gt; default state management choice for React apps. Many of us learned it early, shipped production apps with it, and defended it in code reviews. But here’s the part that often gets ignored: Redux was never designed to manage server state.&lt;/p&gt;

&lt;p&gt;Yet somehow, it became the go-to tool for handling API requests, responses, loading states, caching, retries, and everything in between. And if you’ve ever felt like that setup is exhausting, frustrating, or unnecessarily complex, you’re not imagining things. It really is that bad.&lt;/p&gt;

&lt;p&gt;The good news is that it doesn’t have to be this way. There’s a tool that actually understands server state, and that tool is React Query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Redux Falls Apart With API Calls
&lt;/h3&gt;

&lt;p&gt;Using Redux for request-response data feels a bit like forcing a tool to do a job it was never built for. Yes, it can work, but the friction is constant.&lt;/p&gt;

&lt;p&gt;First, there’s the boilerplate. For a single API call, you define request, success, and failure action types. Then you write action creators. Then reducers. Then middleware like thunk or saga just to make async logic possible. After all that, you still have to manually track loading states, error states, caching behavior, and refetch logic in your UI.&lt;/p&gt;

&lt;p&gt;All of this effort just to fetch data and display it.&lt;/p&gt;

&lt;p&gt;Second, Redux has no concept of stale data. Server data changes over time, but Redux doesn’t know that. If you want fresh data, you have to explicitly tell it when to refetch. That means more logic for pagination, refetch-on-focus, refetch-on-mount, background updates, and avoiding duplicate requests. Miss one edge case, and suddenly your users are looking at outdated data.&lt;/p&gt;

&lt;p&gt;Then there’s the bigger design issue: not all API data belongs in global state. Many API responses are temporary, screen-specific, or tied to a single user flow. Redux forces everything into a global store, which makes debugging harder and bloats your state with data that doesn’t need to live there long-term.&lt;/p&gt;

&lt;p&gt;At some point, you step back and realize you’re fighting the tool instead of using it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where React Query Changes Everything
&lt;/h3&gt;

&lt;p&gt;React Query flips the entire approach. Instead of treating server data like client state, it treats it as what it really is: data that comes from the server and needs to stay in sync with it.&lt;/p&gt;

&lt;p&gt;There’s no boilerplate circus. You write a query, get your data, loading state, and errors from a hook, and move on. No actions. No reducers. No middleware. Just data.&lt;/p&gt;

&lt;p&gt;Caching is automatic. React Query knows when data is fresh, when it’s stale, and when it should refetch. It updates data when users revisit a page, when the browser regains focus, or when a mutation changes something on the server. You don’t write extra logic for this. It just happens.&lt;/p&gt;

&lt;p&gt;Mutations are where the difference really shows. Things like optimistic updates, retries, and error handling that are painful in Redux become straightforward. You describe what should happen, and React Query handles the mechanics.&lt;/p&gt;

&lt;p&gt;The result is code that’s easier to read, easier to reason about, and far less fragile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does This Mean Redux Is Dead?
&lt;/h3&gt;

&lt;p&gt;Not at all. Redux is still useful for client state. UI state, authentication state, feature flags, theme settings, and other global concerns still fit nicely there.&lt;/p&gt;

&lt;p&gt;But server state is a different problem space. Treating it like client state is the mistake. Once you separate the two, things click into place very quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Takeaway
&lt;/h3&gt;

&lt;p&gt;If you’re using Redux for API requests because “that’s how it’s always been done,” it might be time to reassess. There’s no prize for maintaining 500 lines of boilerplate just to fetch data.&lt;/p&gt;

&lt;p&gt;React Query exists because this problem needed a better solution. Less code. Fewer bugs. Better performance. Saner defaults.&lt;/p&gt;

&lt;p&gt;Your future self will appreciate the switch.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
