<?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: Prince Patel</title>
    <description>The latest articles on DEV Community by Prince Patel (@prince_patel_09).</description>
    <link>https://dev.to/prince_patel_09</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%2F4006712%2F7450c1d6-3a8d-4b70-95f6-d57ffee315ba.jpg</url>
      <title>DEV Community: Prince Patel</title>
      <link>https://dev.to/prince_patel_09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prince_patel_09"/>
    <language>en</language>
    <item>
      <title>React State vs Server State: Why You Shouldn't Store Everything in useState</title>
      <dc:creator>Prince Patel</dc:creator>
      <pubDate>Wed, 23 Sep 2026 13:24:10 +0000</pubDate>
      <link>https://dev.to/prince_patel_09/react-state-vs-server-state-why-you-shouldnt-store-everything-in-usestate-19da</link>
      <guid>https://dev.to/prince_patel_09/react-state-vs-server-state-why-you-shouldnt-store-everything-in-usestate-19da</guid>
      <description>&lt;p&gt;I used to think fetching API data in React was pretty straightforward.&lt;/p&gt;

&lt;p&gt;Fetch the data → put it in useState → render it.&lt;br&gt;
And for a small application, it works perfectly fine.&lt;/p&gt;

&lt;p&gt;const [users, setUsers] = useState([]);&lt;/p&gt;

&lt;p&gt;useEffect(() =&amp;gt; {&lt;br&gt;
    fetch("/api/users")&lt;br&gt;
        .then(res =&amp;gt; res.json())&lt;br&gt;
        .then(data =&amp;gt; setUsers(data));&lt;br&gt;
}, []);&lt;/p&gt;

&lt;p&gt;The problem starts when the application grows.&lt;/p&gt;

&lt;p&gt;Suddenly, you need to handle:&lt;/p&gt;

&lt;p&gt;Loading states&lt;br&gt;
Errors&lt;br&gt;
Refetching&lt;br&gt;
Caching&lt;br&gt;
Stale data&lt;br&gt;
Retries&lt;br&gt;
Multiple components using the same data&lt;br&gt;
Keeping server data in sync&lt;/p&gt;

&lt;p&gt;At that point, the question isn't really, "Can I use useState?"&lt;br&gt;
Of course I can.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;p&gt;Who owns this state?&lt;br&gt;
Client State vs Server State : &lt;/p&gt;

&lt;p&gt;Client state is state owned by the UI.&lt;/p&gt;

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

&lt;p&gt;Is a modal open?&lt;br&gt;
Which tab is selected?&lt;br&gt;
What's currently typed in an input?&lt;br&gt;
Which item is selected?&lt;/p&gt;

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

&lt;p&gt;const [isModalOpen, setIsModalOpen] = useState(false);&lt;br&gt;
const [selectedTab, setSelectedTab] = useState("profile");&lt;/p&gt;

&lt;p&gt;useState is a great fit here because the component is responsible for that state.&lt;/p&gt;

&lt;p&gt;Server state is different.&lt;/p&gt;

&lt;p&gt;Think about:&lt;/p&gt;

&lt;p&gt;Users&lt;br&gt;
Products&lt;br&gt;
Orders&lt;br&gt;
Notifications&lt;br&gt;
Comments&lt;br&gt;
Dashboard data&lt;/p&gt;

&lt;p&gt;This data comes from an external source.&lt;/p&gt;

&lt;p&gt;Your React application is essentially consuming a snapshot of data that the server owns.&lt;br&gt;
That means the data can change outside your component.&lt;br&gt;
It can become stale, need to be refetched, or be shared across multiple components. You may also want caching and background updates.&lt;br&gt;
That's where something like TanStack Query becomes useful.&lt;/p&gt;

&lt;p&gt;Instead of manually managing:&lt;/p&gt;

&lt;p&gt;const [users, setUsers] = useState([]);&lt;br&gt;
const [loading, setLoading] = useState(true);&lt;br&gt;
const [error, setError] = useState(null);&lt;/p&gt;

&lt;p&gt;you can let a server-state library handle much of that lifecycle:&lt;/p&gt;

&lt;p&gt;const {&lt;br&gt;
    data: users = [],&lt;br&gt;
    isLoading,&lt;br&gt;
    error&lt;br&gt;
} = useQuery({&lt;br&gt;
    queryKey: ["users"],&lt;br&gt;
    queryFn: getUsers&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Now the responsibility isn't just "store this API response in state."&lt;br&gt;
You're working with data that has a lifecycle:&lt;/p&gt;

&lt;p&gt;fetch → cache → become stale → refetch → update&lt;/p&gt;

&lt;p&gt;That's the part that useState doesn't try to solve.&lt;/p&gt;

&lt;p&gt;So, should we stop using useState?&lt;br&gt;
Definitely not.&lt;/p&gt;

&lt;p&gt;I still use useState for UI state all the time.&lt;br&gt;
The lesson is simply that not all state is the same.&lt;/p&gt;

&lt;p&gt;A useful mental model is:&lt;/p&gt;

&lt;p&gt;UI owns it → useState&lt;br&gt;
Server owns it → consider a server-state solution&lt;/p&gt;

&lt;p&gt;Once I started thinking about state this way, React state management became much easier to reason about.&lt;br&gt;
It's not about replacing useState.&lt;br&gt;
It's about using the right abstraction for the problem you're actually solving.&lt;/p&gt;

&lt;p&gt;Have you had a similar experience where a simple useState + useEffect solution eventually became difficult to maintain?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Infinite Re-render That Froze My App</title>
      <dc:creator>Prince Patel</dc:creator>
      <pubDate>Sat, 01 Aug 2026 06:52:03 +0000</pubDate>
      <link>https://dev.to/prince_patel_09/the-infinite-re-render-that-froze-my-app-aa3</link>
      <guid>https://dev.to/prince_patel_09/the-infinite-re-render-that-froze-my-app-aa3</guid>
      <description>&lt;h1&gt;
  
  
  React’s “Maximum Update Depth Exceeded”: The &lt;code&gt;useEffect&lt;/code&gt; Bug That Caused Hundreds of API Calls
&lt;/h1&gt;

&lt;p&gt;One &lt;code&gt;useEffect&lt;/code&gt; dependency caused my React application to make the same API request &lt;strong&gt;hundreds of times&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The browser became sluggish, CPU usage went up, and eventually React crashed with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum update depth exceeded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, I thought the problem was somewhere in my API or state management.&lt;/p&gt;

&lt;p&gt;It wasn't.&lt;/p&gt;

&lt;p&gt;The problem was hiding inside a small &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happened?
&lt;/h2&gt;

&lt;p&gt;Everything looked normal at first.&lt;/p&gt;

&lt;p&gt;The application compiled successfully.&lt;br&gt;
There were no syntax errors.&lt;br&gt;
The UI loaded correctly.&lt;/p&gt;

&lt;p&gt;Then I clicked a button.&lt;/p&gt;

&lt;p&gt;A few seconds later, the application started slowing down.&lt;/p&gt;

&lt;p&gt;I opened Chrome DevTools and checked the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;That's when I noticed something strange:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The same API request was being sent repeatedly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not twice.&lt;/p&gt;

&lt;p&gt;Not ten times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hundreds of times.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every response seemed to trigger another render, which triggered another request.&lt;/p&gt;

&lt;p&gt;So I started tracing the component to find out what was causing the loop.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Culprit: &lt;code&gt;useEffect&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I eventually found code similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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;setUsers&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="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;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setUsers&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, the effect looks reasonable.&lt;/p&gt;

&lt;p&gt;But look carefully at the dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The effect depends on &lt;code&gt;users&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But inside the effect, we're also updating &lt;code&gt;users&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;setUsers&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That creates a cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does It Loop?
&lt;/h2&gt;

&lt;p&gt;Here's what happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Component renders
       ↓
useEffect runs
       ↓
API request starts
       ↓
Data comes back
       ↓
setUsers(data)
       ↓
users changes
       ↓
Component renders again
       ↓
useEffect runs again
       ↓
Another API request
       ↓
... repeat ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, React throws:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum update depth exceeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important thing to remember is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If an effect updates a state value that the same effect depends on, you may have created a render loop.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;In this case, the effect only needed to fetch the users when the component mounted.&lt;/p&gt;

&lt;p&gt;So the dependency array should not listen to &lt;code&gt;users&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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;setUsers&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="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;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setUsers&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="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 the flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Component renders
       ↓
useEffect runs once
       ↓
API request
       ↓
setUsers(data)
       ↓
Component renders
       ↓
useEffect does NOT run again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One request instead of hundreds.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dependency Array Mental Model
&lt;/h2&gt;

&lt;p&gt;Whenever I write a new &lt;code&gt;useEffect&lt;/code&gt;, I now think about it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dependency changes
       ↓
Effect runs
       ↓
Does the effect update that dependency?
       ↓
       YES
       ↓
Could the effect trigger itself again?
       ↓
       ⚠️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That simple check can prevent a lot of debugging pain.&lt;/p&gt;

&lt;p&gt;The dependency array isn't just a list of values you happen to use.&lt;/p&gt;

&lt;p&gt;It determines &lt;strong&gt;when React should run the effect again&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common &lt;code&gt;useEffect&lt;/code&gt; Mistake
&lt;/h2&gt;

&lt;p&gt;A common pattern is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="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;setSomething&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="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;something&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 an effect structured like this, stop and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What happens after this state changes?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If changing the state causes the effect to run again, you need to make sure the cycle has a valid stopping condition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before vs After
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Browser became unresponsive&lt;/li&gt;
&lt;li&gt;Hundreds of API requests&lt;/li&gt;
&lt;li&gt;High CPU usage&lt;/li&gt;
&lt;li&gt;Repeated renders&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Maximum update depth exceeded&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Poor user experience&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;One API request&lt;/li&gt;
&lt;li&gt;Stable rendering&lt;/li&gt;
&lt;li&gt;Smooth navigation&lt;/li&gt;
&lt;li&gt;Lower unnecessary CPU usage&lt;/li&gt;
&lt;li&gt;Cleaner component logic&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This bug reinforced a few React fundamentals for me:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Every state update can trigger another render.&lt;/strong&gt;&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;setUsers&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;doesn't just change a variable. It causes React to render the component again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Dependencies control when an effect runs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A dependency changing can cause the effect to execute again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Be careful when an effect changes one of its own dependencies.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That combination can easily create an infinite loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Don't add dependencies blindly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal isn't to make the dependency array longer.&lt;/p&gt;

&lt;p&gt;The goal is to correctly describe &lt;strong&gt;when the effect needs to run&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Could Monitoring Have Helped?
&lt;/h2&gt;

&lt;p&gt;Performance and error-monitoring tools can make problems like this easier to investigate.&lt;/p&gt;

&lt;p&gt;For example, monitoring can help identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeated errors&lt;/li&gt;
&lt;li&gt;Excessive network activity&lt;/li&gt;
&lt;li&gt;Performance degradation&lt;/li&gt;
&lt;li&gt;Session behaviour before the crash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That can significantly reduce the time needed to find the root cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;This wasn't caused by a complicated algorithm or an obscure library.&lt;/p&gt;

&lt;p&gt;It came from a tiny dependency mistake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's what makes React bugs like this interesting.&lt;/p&gt;

&lt;p&gt;A small change can create a surprisingly large performance problem.&lt;/p&gt;

&lt;p&gt;Now, whenever I write a new &lt;code&gt;useEffect&lt;/code&gt;, I ask myself one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Could this effect accidentally trigger itself?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question has already saved me from repeating this mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you ever encountered an infinite &lt;code&gt;useEffect&lt;/code&gt; loop? What caused yours?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Fixing a Memory Leak in React by Cleaning Up useEffect</title>
      <dc:creator>Prince Patel</dc:creator>
      <pubDate>Sat, 01 Aug 2026 06:20:17 +0000</pubDate>
      <link>https://dev.to/prince_patel_09/fixing-a-memory-leak-in-react-by-cleaning-up-useeffect-4ifl</link>
      <guid>https://dev.to/prince_patel_09/fixing-a-memory-leak-in-react-by-cleaning-up-useeffect-4ifl</guid>
      <description>&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;The project is a React-based web application that fetches data from a REST API and displays it in a dynamic dashboard. Users can navigate between pages, search data, and interact with multiple components that rely on asynchronous API calls.&lt;/p&gt;

&lt;p&gt;While testing the application, I noticed that navigating away from a page during an active API request occasionally caused React warnings and unnecessary memory usage. This issue affected the application's stability and could lead to performance degradation over time.&lt;/p&gt;

&lt;p&gt;The problem was caused by an asynchronous operation continuing even after the component had been unmounted.&lt;/p&gt;

&lt;p&gt;For example, an API request initiated inside useEffect would still complete after the user navigated away, attempting to update the component's state. React would warn that a state update was attempted on an unmounted component.&lt;/p&gt;

&lt;p&gt;Before&lt;br&gt;
useEffect(() =&amp;gt; {&lt;br&gt;
  fetch("/api/users")&lt;br&gt;
    .then((res) =&amp;gt; res.json())&lt;br&gt;
    .then((data) =&amp;gt; setUsers(data));&lt;br&gt;
}, []);&lt;/p&gt;

&lt;p&gt;If the component unmounted before the request finished, the callback still attempted to update the state.&lt;/p&gt;

&lt;p&gt;After&lt;/p&gt;

&lt;p&gt;I solved the issue by using the AbortController API to cancel the request during cleanup.&lt;/p&gt;

&lt;p&gt;useEffect(() =&amp;gt; {&lt;br&gt;
  const controller = new AbortController();&lt;/p&gt;

&lt;p&gt;fetch("/api/users", {&lt;br&gt;
    signal: controller.signal,&lt;br&gt;
  })&lt;br&gt;
    .then((res) =&amp;gt; res.json())&lt;br&gt;
    .then((data) =&amp;gt; setUsers(data))&lt;br&gt;
    .catch((err) =&amp;gt; {&lt;br&gt;
      if (err.name !== "AbortError") {&lt;br&gt;
        console.error(err);&lt;br&gt;
      }&lt;br&gt;
    });&lt;/p&gt;

&lt;p&gt;return () =&amp;gt; controller.abort();&lt;br&gt;
}, []);&lt;/p&gt;

&lt;p&gt;This ensures that pending requests are cancelled when the component unmounts, preventing unnecessary state updates and avoiding memory leaks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://github.com/Prince3963?tab=repositories" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F177241333%3Fv%3D4%3Fs%3D400" height="460" class="m-0" width="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://github.com/Prince3963?tab=repositories" rel="noopener noreferrer" class="c-link"&gt;
            Prince3963 (Patel Prince) / Repositories · GitHub
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Prince3963 has 48 repositories available. Follow their code on GitHub.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.githubassets.com%2Ffavicons%2Ffavicon.svg" width="32" height="32"&gt;
          github.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;This fix focused on improving both performance and application reliability.&lt;/p&gt;

&lt;p&gt;What I improved&lt;br&gt;
Prevented memory leaks caused by unfinished asynchronous requests.&lt;br&gt;
Added proper cleanup logic inside useEffect.&lt;br&gt;
Eliminated React warnings about updating unmounted components.&lt;br&gt;
Reduced unnecessary memory consumption.&lt;br&gt;
Improved the user experience during rapid page navigation.&lt;br&gt;
Followed React best practices for handling asynchronous operations.&lt;br&gt;
Technical Approach&lt;/p&gt;

&lt;p&gt;Instead of allowing every request to complete regardless of component lifecycle, I introduced request cancellation using AbortController. This is a lightweight and native browser solution that integrates well with the Fetch API.&lt;/p&gt;

&lt;p&gt;I also added proper error handling to ignore expected AbortError exceptions while still logging genuine network failures.&lt;/p&gt;

&lt;p&gt;The resulting code is cleaner, safer, and easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Use of Sentry
&lt;/h2&gt;

&lt;p&gt;Although this particular fix was implemented without extensive observability tooling, it would integrate well with Sentry's Error Monitoring and Performance Monitoring.&lt;/p&gt;

&lt;p&gt;Sentry could help by:&lt;/p&gt;

&lt;p&gt;Detecting repeated React warnings.&lt;br&gt;
Tracking failed API requests.&lt;br&gt;
Monitoring slow network operations.&lt;br&gt;
Identifying components generating frequent runtime errors.&lt;br&gt;
Providing stack traces to simplify debugging.&lt;/p&gt;

&lt;p&gt;These insights would make it easier to identify similar issues in production before they impact users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Use of Google AI
&lt;/h2&gt;

&lt;p&gt;Google AI can significantly speed up debugging and code improvement by:&lt;/p&gt;

&lt;p&gt;Explaining React lifecycle behavior.&lt;br&gt;
Suggesting safer asynchronous patterns.&lt;br&gt;
Recommending performance optimizations.&lt;br&gt;
Reviewing cleanup logic for hooks.&lt;br&gt;
Helping developers understand why memory leaks occur and how to prevent them.&lt;/p&gt;

&lt;p&gt;Using AI as a development assistant can reduce debugging time while promoting best practices.&lt;/p&gt;

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

&lt;p&gt;Memory leaks are often difficult to notice because an application may appear to work correctly until users begin navigating frequently or using it for extended periods.&lt;/p&gt;

&lt;p&gt;A small cleanup function inside useEffect can prevent unnecessary memory usage, eliminate React warnings, and improve overall application stability.&lt;/p&gt;

&lt;p&gt;This contribution reinforced an important React principle: every side effect should also have a cleanup strategy.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and happy debugging!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>react</category>
      <category>frontendchallenge</category>
    </item>
    <item>
      <title>PassionForge AI</title>
      <dc:creator>Prince Patel</dc:creator>
      <pubDate>Sat, 11 Jul 2026 06:54:53 +0000</pubDate>
      <link>https://dev.to/prince_patel_09/passionforge-ai-457k</link>
      <guid>https://dev.to/prince_patel_09/passionforge-ai-457k</guid>
      <description>&lt;h1&gt;
  
  
  This is a submission for &lt;strong&gt;Weekend Challenge: Passion Edition&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What I Want to Build
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PassionForge AI&lt;/strong&gt; is an AI-powered platform that I want to build to help people transform their passions into real projects, careers, or businesses.&lt;/p&gt;

&lt;p&gt;Many people know what they love—whether it's coding, photography, music, sports, writing, fitness, or art—but they often don't know where to begin. PassionForge AI will act as a personal AI mentor, creating a customized roadmap based on each user's interests, experience level, available time, and long-term goals.&lt;/p&gt;

&lt;p&gt;Instead of providing generic advice, the platform will generate a personalized action plan that helps users:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discover the best learning path&lt;/li&gt;
&lt;li&gt;Find the right AI tools for their journey&lt;/li&gt;
&lt;li&gt;Build real-world projects&lt;/li&gt;
&lt;li&gt;Stay motivated with milestones and progress tracking&lt;/li&gt;
&lt;li&gt;Explore ways to share or monetize their passion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn't simply to recommend AI tools. I want PassionForge AI to help people take meaningful action toward something they genuinely care about.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ASP.NET Core Web API (.NET)&lt;/li&gt;
&lt;li&gt;Entity Framework Core&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;JWT Authentication&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Google Gemini API&lt;/li&gt;
&lt;li&gt;Claude&lt;/li&gt;
&lt;li&gt;ChatGPT (Codex)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How I Want to Build It
&lt;/h2&gt;

&lt;p&gt;I want to create something that fits the challenge theme in a practical and meaningful way.&lt;/p&gt;

&lt;p&gt;Rather than building another AI chatbot, I want PassionForge AI to become a personalized mentor that guides users throughout their journey.&lt;/p&gt;

&lt;p&gt;The application will begin by understanding the user's passion and collecting information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current skill level&lt;/li&gt;
&lt;li&gt;Weekly time commitment&lt;/li&gt;
&lt;li&gt;Long-term goal&lt;/li&gt;
&lt;li&gt;Preferred learning style&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using Google Gemini, the platform will generate a personalized roadmap that includes learning recommendations, project ideas, suitable AI tools, and milestone-based guidance.&lt;/p&gt;

&lt;p&gt;The backend will be developed using ASP.NET Core Web API with a clean layered architecture. PostgreSQL will be used to store user profiles, passions, personalized roadmaps, and progress data, while JWT Authentication will secure user sessions. The frontend will be built using React and Tailwind CSS to provide a modern, responsive, and intuitive user experience.&lt;/p&gt;

&lt;p&gt;One of the most exciting challenges will be designing AI prompts that generate actionable guidance instead of generic motivational responses. My goal is to ensure the AI produces structured, practical, and realistic plans that users can confidently follow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best Use of Google AI
&lt;/h3&gt;

&lt;p&gt;Google Gemini will be the core intelligence behind PassionForge AI.&lt;/p&gt;

&lt;p&gt;I also plan to leverage Claude and ChatGPT (Codex) during development to improve prompts, development workflow, and overall implementation.&lt;/p&gt;

&lt;p&gt;Google Gemini will be responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating personalized passion roadmaps&lt;/li&gt;
&lt;li&gt;Recommending relevant AI tools&lt;/li&gt;
&lt;li&gt;Suggesting learning resources&lt;/li&gt;
&lt;li&gt;Creating milestone-based action plans&lt;/li&gt;
&lt;li&gt;Recommending project ideas based on user interests&lt;/li&gt;
&lt;li&gt;Providing guidance tailored to each user's goals and experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI won't simply be an additional feature—it will power the entire personalized experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;I want to deploy the application so it can be accessed from different devices and tested in real-world scenarios.&lt;/p&gt;

&lt;p&gt;My deployment plan includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploying the frontend and backend to the cloud&lt;/li&gt;
&lt;li&gt;Testing the application across multiple devices and browsers&lt;/li&gt;
&lt;li&gt;Purchasing a custom domain for a professional experience&lt;/li&gt;
&lt;li&gt;Ensuring a smooth and responsive user experience after deployment&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why I Want to Build This
&lt;/h2&gt;

&lt;p&gt;Passion is where many great ideas begin, but countless people never take the first step because they don't know what to do next.&lt;/p&gt;

&lt;p&gt;Through PassionForge AI, I want to bridge the gap between inspiration and execution.&lt;/p&gt;

&lt;p&gt;Whether someone dreams of becoming a developer, photographer, creator, athlete, entrepreneur, or artist, I want this platform to provide a practical roadmap that helps them move forward—one meaningful step at a time.&lt;/p&gt;

&lt;p&gt;My goal is to build a platform that inspires people to invest in what they truly love and gives them the confidence and guidance to turn their passion into something meaningful.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>passionedition</category>
      <category>ai</category>
    </item>
    <item>
      <title>Repository Pattern Explained Without Confusion</title>
      <dc:creator>Prince Patel</dc:creator>
      <pubDate>Sun, 28 Jun 2026 17:25:36 +0000</pubDate>
      <link>https://dev.to/prince_patel_09/repository-pattern-explained-without-confusion-4mjo</link>
      <guid>https://dev.to/prince_patel_09/repository-pattern-explained-without-confusion-4mjo</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%2F1ij86kf0tfej1kiehyy4.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%2F1ij86kf0tfej1kiehyy4.jpg" alt=" " width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever written database queries directly inside your controllers and later wondered why your code became difficult to maintain?&lt;/p&gt;

&lt;p&gt;I made the same mistake when I first started learning ASP.NET Core. At first, everything worked fine. But as my project grew, controllers became bloated, database logic was scattered everywhere, and making changes became frustrating.&lt;/p&gt;

&lt;p&gt;That's when I discovered the &lt;strong&gt;Repository Pattern&lt;/strong&gt;—a simple design pattern that separates data access from business logic, making applications cleaner, easier to maintain, and much easier to test.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain the Repository Pattern in the simplest way possible—with real examples, diagrams, and practical ASP.NET Core code.&lt;/p&gt;




&lt;h1&gt;
  
  
  What You'll Learn
&lt;/h1&gt;

&lt;p&gt;By the end of this article, you'll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the Repository Pattern is&lt;/li&gt;
&lt;li&gt;Why developers use it&lt;/li&gt;
&lt;li&gt;Problems it solves&lt;/li&gt;
&lt;li&gt;How it fits into an ASP.NET Core application&lt;/li&gt;
&lt;li&gt;How to implement it step by step&lt;/li&gt;
&lt;li&gt;Advantages and disadvantages&lt;/li&gt;
&lt;li&gt;Common mistakes to avoid&lt;/li&gt;
&lt;li&gt;Best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;When beginners start building APIs, it's common to write code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&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="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetProducts&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="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&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;At first glance, this looks perfectly fine.&lt;/p&gt;

&lt;p&gt;So what's wrong?&lt;/p&gt;

&lt;p&gt;The controller is directly communicating with the database.&lt;/p&gt;

&lt;p&gt;This creates several problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The controller now has two responsibilities.&lt;/li&gt;
&lt;li&gt;Business logic and data access become mixed together.&lt;/li&gt;
&lt;li&gt;Unit testing becomes difficult.&lt;/li&gt;
&lt;li&gt;Any database-related changes require modifications inside the controller.&lt;/li&gt;
&lt;li&gt;As your application grows, controllers become large and difficult to maintain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In small projects this might not matter.&lt;/p&gt;

&lt;p&gt;In large projects, it becomes a nightmare.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is the Repository Pattern?
&lt;/h1&gt;

&lt;p&gt;The &lt;strong&gt;Repository Pattern&lt;/strong&gt; acts as a middle layer between your application and the database.&lt;/p&gt;

&lt;p&gt;Instead of allowing controllers to communicate directly with Entity Framework, controllers interact with a &lt;strong&gt;Repository&lt;/strong&gt;, and the repository handles all database operations.&lt;/p&gt;

&lt;p&gt;This creates a clear separation of responsibilities.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Simple Analogy
&lt;/h1&gt;

&lt;p&gt;Imagine you're eating at a restaurant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customer → Controller&lt;/li&gt;
&lt;li&gt;Waiter → Repository&lt;/li&gt;
&lt;li&gt;Kitchen → Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The customer never walks into the kitchen to cook food.&lt;/p&gt;

&lt;p&gt;Instead, they tell the waiter what they want.&lt;/p&gt;

&lt;p&gt;The waiter communicates with the kitchen and returns with the food.&lt;/p&gt;

&lt;p&gt;The Repository works exactly the same way.&lt;/p&gt;

&lt;p&gt;The controller simply asks the repository for data, and the repository communicates with the database.&lt;/p&gt;




&lt;h1&gt;
  
  
  Architecture
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
   │
   ▼
Controller
   │
   ▼
Service
   │
   ▼
Repository
   │
   ▼
DbContext
   │
   ▼
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer has a single responsibility:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Controller&lt;/td&gt;
&lt;td&gt;Handle HTTP requests and responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Business logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository&lt;/td&gt;
&lt;td&gt;Database operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DbContext&lt;/td&gt;
&lt;td&gt;Communicate with Entity Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Store application data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This separation makes the application much easier to maintain.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 1: Create the Repository Interface
&lt;/h1&gt;

&lt;p&gt;The interface defines the operations our repository should support.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IProductRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;UpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&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;Using an interface allows us to change the implementation later without affecting the controller.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 2: Implement the Repository
&lt;/h1&gt;

&lt;p&gt;Now let's implement the interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IProductRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllAsync&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// UpdateAsync() and DeleteAsync() would follow the same pattern.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that all database-related code now lives inside the repository instead of the controller.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 3: Register Dependency Injection
&lt;/h1&gt;

&lt;p&gt;Register the repository in &lt;strong&gt;Program.cs&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IProductRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProductRepository&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;Now ASP.NET Core knows which implementation to provide whenever &lt;code&gt;IProductRepository&lt;/code&gt; is requested.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 4: Use the Repository in the Controller
&lt;/h1&gt;

&lt;p&gt;Now our controller becomes much cleaner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IProductRepository&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IProductRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_repository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&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="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetProducts&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="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAllAsync&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;The controller no longer needs to know anything about &lt;code&gt;DbContext&lt;/code&gt; or Entity Framework.&lt;/p&gt;

&lt;p&gt;Its only responsibility is handling HTTP requests.&lt;/p&gt;




&lt;h1&gt;
  
  
  Benefits
&lt;/h1&gt;

&lt;p&gt;Using the Repository Pattern provides several advantages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaner code structure&lt;/li&gt;
&lt;li&gt;Better separation of concerns&lt;/li&gt;
&lt;li&gt;Easier unit testing&lt;/li&gt;
&lt;li&gt;Reusable data access logic&lt;/li&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;li&gt;Better scalability&lt;/li&gt;
&lt;li&gt;Reduced code duplication&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Common Mistakes
&lt;/h1&gt;

&lt;p&gt;Avoid these common mistakes:&lt;/p&gt;

&lt;p&gt;Putting business logic inside repositories&lt;br&gt;
Returning &lt;code&gt;IQueryable&lt;/code&gt; everywhere&lt;br&gt;
Injecting both &lt;code&gt;DbContext&lt;/code&gt; and the repository into the same controller&lt;br&gt;
Creating one giant repository for every entity&lt;/p&gt;

&lt;p&gt;Remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository = Data Access&lt;/li&gt;
&lt;li&gt;Service = Business Logic&lt;/li&gt;
&lt;li&gt;Controller = HTTP Requests&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Best Practices
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Keep repositories focused only on database operations.&lt;/li&gt;
&lt;li&gt;Keep business logic inside the Service layer.&lt;/li&gt;
&lt;li&gt;Use asynchronous methods whenever possible.&lt;/li&gt;
&lt;li&gt;Program against interfaces instead of concrete classes.&lt;/li&gt;
&lt;li&gt;Use Dependency Injection.&lt;/li&gt;
&lt;li&gt;Keep repositories small and focused.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  When Should You Use the Repository Pattern?
&lt;/h1&gt;

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

&lt;ul&gt;
&lt;li&gt;You're building medium or large applications.&lt;/li&gt;
&lt;li&gt;Multiple developers are working on the project.&lt;/li&gt;
&lt;li&gt;You want clean architecture.&lt;/li&gt;
&lt;li&gt;You need unit testing.&lt;/li&gt;
&lt;li&gt;You expect the project to grow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For very small CRUD applications or quick prototypes, directly using &lt;code&gt;DbContext&lt;/code&gt; may be sufficient.&lt;/p&gt;

&lt;p&gt;Choose the level of abstraction that fits your project's complexity.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The Repository Pattern isn't about writing more code—it's about writing better-organized code.&lt;/p&gt;

&lt;p&gt;By separating database operations from controllers, your application becomes cleaner, easier to test, and much easier to maintain as it grows.&lt;/p&gt;

&lt;p&gt;If you're serious about becoming an ASP.NET Core developer, understanding the Repository Pattern is an important step toward writing production-ready applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  What do you think?
&lt;/h2&gt;

&lt;p&gt;Do you use the Repository Pattern in your ASP.NET Core projects?&lt;br&gt;
Or do you prefer working directly with &lt;code&gt;DbContext&lt;/code&gt;?&lt;br&gt;
Let me know in the comments—I’d love to hear your thoughts.&lt;br&gt;
If you found this article helpful, consider leaving a love and following me for more beginner-friendly ASP.NET Core tutorials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next in this series:&lt;/strong&gt; Dependency Injection Explained Without Confusion&lt;/p&gt;

&lt;h1&gt;
  
  
  dotnet #aspnetcore #csharp #webdev
&lt;/h1&gt;

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