{"id":4812,"date":"2026-06-10T23:41:43","date_gmt":"2026-06-10T18:11:43","guid":{"rendered":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/"},"modified":"2026-06-10T23:41:43","modified_gmt":"2026-06-10T18:11:43","slug":"10-react-best-practices-for-writing-cleaner-code-in-2024","status":"publish","type":"post","link":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/","title":{"rendered":"10 React Best Practices for Writing Cleaner Code in 2024"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_80 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a29c82fb6540\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a29c82fb6540\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#React_is_Not_a_Framework_Its_a_Debt_Generator_And_How_to_Stop_the_Bleeding\" >React is Not a Framework, It\u2019s a Debt Generator (And How to Stop the Bleeding)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#The_Documentation_is_Lying_to_You\" >The Documentation is Lying to You<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#State_Management_Stop_the_Global_Bloat\" >State Management: Stop the Global Bloat<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#The_useEffect_Footgun\" >The useEffect Footgun<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#Performance_The_Myth_of_useMemo\" >Performance: The Myth of useMemo<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#Folder_Structure_Features_Over_Types\" >Folder Structure: Features Over Types<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#The_%E2%80%9CZ-Index_Hell%E2%80%9D_and_Portals\" >The &#8220;Z-Index Hell&#8221; and Portals<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#Testing_Stop_Testing_Implementation_Details\" >Testing: Stop Testing Implementation Details<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#The_Hydration_Mismatch_Nightmare\" >The Hydration Mismatch Nightmare<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#Data_Fetching_The_Stripe_Example\" >Data Fetching: The Stripe Example<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#The_%E2%80%9CGod_Component%E2%80%9D_Anti-Pattern\" >The &#8220;God Component&#8221; Anti-Pattern<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#Observability_The_SREs_View_of_React\" >Observability: The SRE&#8217;s View of React<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#The_Final_Word_on_%E2%80%9CReact_Best%E2%80%9D\" >The Final Word on &#8220;React Best&#8221;<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#Related_Articles\" >Related Articles<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"React_is_Not_a_Framework_Its_a_Debt_Generator_And_How_to_Stop_the_Bleeding\"><\/span>React is Not a Framework, It\u2019s a Debt Generator (And How to Stop the Bleeding)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Three years ago, I was paged at 2:14 AM on a Tuesday. Our main logistics dashboard, the one the warehouse teams use to track every single shipment across the Atlantic, had turned into a space heater. The browser was consuming 6.2GB of RAM. The CPU was pegged at 100%. The culprit? A &#8220;senior&#8221; frontend lead had decided that the <strong>react best<\/strong> way to handle real-time updates was to shove a WebSocket stream directly into a global Redux store without any throttling or memoization. Every time a package moved an inch in a warehouse in Rotterdam, every single component on the dashboard re-rendered. The DOM couldn&#8217;t keep up. The browser&#8217;s main thread was locked in a death spiral of reconciliation. We had to kill the service worker and force a cache-bust just to get the warehouse back online. It wasn&#8217;t a backend failure. It wasn&#8217;t a database deadlock. It was just bad React.<\/p>\n<p>Most React tutorials are written by people who build Todo apps. They don&#8217;t build systems that stay alive for five years under heavy load. They talk about &#8220;clean code&#8221; while ignoring the fact that their <code>useEffect<\/code> hooks are essentially infinite loops waiting to happen. If you want to build something that doesn&#8217;t require an SRE to wake up in the middle of the night, you need to stop following the &#8220;standard&#8221; advice and start looking at the actual cost of your abstractions.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Documentation_is_Lying_to_You\"><\/span>The Documentation is Lying to You<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>React\u2019s official documentation is great for getting started, but it\u2019s dangerously optimistic. It presents hooks as this magical way to handle state, but it rarely discusses the &#8220;Zombie Child&#8221; problem or the performance tax of the Context API. Most developers treat <code>useContext<\/code> as a replacement for Redux. It isn&#8217;t. Context is a dependency injection tool, not a state management engine. When you update a value in a Context provider, every single consumer re-renders. Period. There is no built-in selector logic to bail out of updates. If you put your entire app state in one giant <code>AppContext<\/code>, you\u2019ve just built a slower version of 1990s-era global variables.<\/p>\n<blockquote><p>\n  Pro-tip: If you find yourself nesting more than three Context providers, you\u2019ve officially entered &#8220;Provider Hell.&#8221; Your component tree is now a brittle mess that is impossible to unit test without mocking half the universe.\n<\/p><\/blockquote>\n<p>The industry is obsessed with &#8220;clean&#8221; looking code, but in React, &#8220;clean&#8221; often means &#8220;hidden side effects.&#8221; I\u2019ve seen developers replace a 10-line <code>fetch<\/code> call with a 500-line custom hook abstraction that makes it impossible to track where the data is actually coming from. We need to get back to basics: predictable data flow and explicit dependencies.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"State_Management_Stop_the_Global_Bloat\"><\/span>State Management: Stop the Global Bloat<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The <strong>react best<\/strong> practice for state is simple: keep it as local as humanly possible. If a piece of state is only used by two components, don&#8217;t put it in a store. Pass the props. Yes, prop drilling is annoying, but it\u2019s explicit. You can look at a component and see exactly what it needs to function. When you hide everything behind a <code>useSelector<\/code> or a <code>useContext<\/code>, you\u2019re making the component a black box that\u2019s tied to a specific environment.<\/p>\n<ul>\n<li><strong>Local State:<\/strong> Use <code>useState<\/code> for UI toggles, form inputs, and anything that doesn&#8217;t need to survive a page refresh.<\/li>\n<li><strong>Server State:<\/strong> Stop using <code>useEffect<\/code> to fetch data. Use TanStack Query (formerly React Query). It handles caching, de-duplication, and loading states out of the box.<\/li>\n<li><strong>Global State:<\/strong> If you actually have global data (like user auth or theme), use Zustand. It\u2019s 1KB, has no boilerplate, and doesn&#8217;t suffer from the Context re-render trap.<\/li>\n<li><strong>URL State:<\/strong> The URL is the most underutilized state manager. Use search params for filters, pagination, and tabs. It makes the &#8220;Back&#8221; button actually work.<\/li>\n<\/ul>\n<pre><code>\/\/ Bad: Putting everything in a global store\nconst { filter } = useSelector(state => state.dashboard);\n\n\/\/ Good: Using the URL as the source of truth\nconst [searchParams, setSearchParams] = useSearchParams();\nconst filter = searchParams.get('status') || 'all';\n\nconst updateFilter = (newStatus) => {\n  setSearchParams({ status: newStatus });\n};\n<\/code><\/pre>\n<p>I once saw a team spend two weeks debugging why a search filter wasn&#8217;t clearing when the user clicked the logo to go home. It was because the filter was stuck in a Redux store that persisted across routes. If they had used the URL, the problem wouldn&#8217;t have existed. The state would have vanished the moment the route changed. That&#8217;s the difference between &#8220;clever&#8221; code and resilient code.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_useEffect_Footgun\"><\/span>The <code>useEffect<\/code> Footgun<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If I could delete one thing from the React API, it would be the <code>useEffect<\/code> hook. It is the source of 90% of the bugs I see in production. Developers use it as a catch-all for &#8220;do something when this changes,&#8221; but they forget that React is a declarative UI library, not an imperative event emitter. When you use <code>useEffect<\/code> to sync two pieces of state, you\u2019re creating a &#8220;split brain&#8221; problem where your UI can get out of sync with your data.<\/p>\n<p>Consider this nightmare I found in a checkout flow on <code>api.stripe.com<\/code> integration code:<\/p>\n<pre><code>useEffect(() => {\n  if (cartItems.length > 0) {\n    setTotal(cartItems.reduce((acc, item) => acc + item.price, 0));\n  }\n}, [cartItems]);\n<\/code><\/pre>\n<p>This is redundant. You don&#8217;t need an effect to calculate the total. You can just calculate it during the render. By using an effect, you&#8217;re forcing React to render once with the old total, then immediately render again with the new total. On a slow mobile device, the user will see the price flicker. Worse, if you have other effects listening to <code>total<\/code>, you\u2019ve just started a chain reaction of re-renders that can easily lead to an OOM-kill on lower-end Android phones.<\/p>\n<p><strong>The Rule:<\/strong> If you can calculate something during render, do it. If you need to handle an event (like a click or a form submission), put that logic in the event handler, not an effect. Effects should only be used to synchronize your component with <em>external<\/em> systems\u2014like a WebSocket, a <code>canvas<\/code> element, or a legacy jQuery plugin that your boss won&#8217;t let you delete.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Performance_The_Myth_of_useMemo\"><\/span>Performance: The Myth of <code>useMemo<\/code><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I see people wrapping every single function in <code>useCallback<\/code> and every object in <code>useMemo<\/code>. They think they&#8217;re being &#8220;performant.&#8221; They aren&#8217;t. They&#8217;re just adding overhead to the initial render. React is incredibly fast at comparing virtual DOM trees. The overhead of creating a memoized function and checking its dependency array is often higher than just re-creating the function.<\/p>\n<p>Don&#8217;t optimize until you have a trace. Open the Chrome DevTools, go to the &#8220;Performance&#8221; tab, and look for the long yellow bars. If a component is taking 100ms to render, then sure, memoize the expensive calculation. But if it&#8217;s taking 2ms, leave it alone. You&#8217;re making the code harder to read for zero gain.<\/p>\n<blockquote><p>\n  Note to self: Stop trying to fix re-renders by adding <code>React.memo<\/code> to every component. Fix the re-renders by moving the state lower down the tree so the parent doesn&#8217;t update in the first place.\n<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"Folder_Structure_Features_Over_Types\"><\/span>Folder Structure: Features Over Types<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If your project looks like this, you\u2019ve already lost:<\/p>\n<pre><code>src\/\n  components\/\n  hooks\/\n  utils\/\n  pages\/\n<\/code><\/pre>\n<p>This is &#8220;Type-based&#8221; organization, and it\u2019s a nightmare for maintainability. When I&#8217;m working on the &#8220;Billing&#8221; feature, I don&#8217;t want to jump between four different top-level folders to find the logic. I want everything related to billing in one place. The <strong>react best<\/strong> way to organize a large-scale app is &#8220;Feature-based&#8221; architecture.<\/p>\n<pre><code>src\/\n  features\/\n    billing\/\n      components\/\n      hooks\/\n      api\/\n      types.ts\n      index.ts\n    auth\/\n    shipping\/\n  shared\/\n    components\/\n    ui\/\n<\/code><\/pre>\n<p>This structure allows you to treat features as mini-applications. You can even enforce boundaries using ESLint rules to prevent <code>features\/auth<\/code> from importing things from <code>features\/billing<\/code>. This prevents the &#8220;Spaghetti Dependency&#8221; mess where changing a button in the login flow somehow breaks the checkout page. I&#8217;ve seen YAML-hell in K8s configs that was easier to parse than a poorly structured React <code>src<\/code> folder.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_%E2%80%9CZ-Index_Hell%E2%80%9D_and_Portals\"><\/span>The &#8220;Z-Index Hell&#8221; and Portals<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Every SRE has a story about a &#8220;Critical Alert&#8221; modal that was hidden behind a sidebar because of a <code>z-index<\/code> conflict. CSS in React is still a mess, whether you use Tailwind, Styled Components, or CSS Modules. The problem isn&#8217;t the styling; it&#8217;s the DOM hierarchy. If you have a modal nested deep inside a <code>div<\/code> with <code>overflow: hidden<\/code>, your modal is going to get clipped. No amount of <code>z-index: 999999<\/code> will save you.<\/p>\n<p>Use <code>createPortal<\/code>. Always. Modals, tooltips, and dropdowns should be rendered at the root of the document, outside of the main app hierarchy. This avoids stacking context issues and makes your UI significantly more predictable.<\/p>\n<pre><code>\/\/ The right way to do a Modal\nimport { createPortal } from 'react-dom';\n\nconst Modal = ({ children }) => {\n  return createPortal(\n    &lt;div className=\"modal-overlay\"&gt;\n      {children}\n    &lt;\/div&gt;,\n    document.getElementById('modal-root')\n  );\n};\n<\/code><\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Testing_Stop_Testing_Implementation_Details\"><\/span>Testing: Stop Testing Implementation Details<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I\u2019ve seen test suites with 95% coverage that still allow critical bugs into production. Why? Because the tests are checking <em>how<\/em> the code works, not <em>what<\/em> it does. If your test checks that a specific state variable changes from <code>false<\/code> to <code>true<\/code>, your test is useless. The user doesn&#8217;t care about your state variables. They care if the button works.<\/p>\n<ul>\n<li><strong>Don&#8217;t:<\/strong> Use Enzyme to shallow-render components and inspect their internal state.<\/li>\n<li><strong>Do:<\/strong> Use React Testing Library to find elements by their role (e.g., <code>getByRole('button', { name: \/submit\/i })<\/code>) and simulate user events.<\/li>\n<li><strong>Don&#8217;t:<\/strong> Unit test every single 5-line utility function.<\/li>\n<li><strong>Do:<\/strong> Write integration tests for the &#8220;Happy Path&#8221; of your features. Can the user log in? Can they add an item to the cart? Can they pay?<\/li>\n<li><strong>Pro-tip:<\/strong> Use Playwright for E2E tests. It\u2019s faster than Cypress, has better debugging tools, and doesn&#8217;t flake out as much when running in a CI\/CD pipeline on GitHub Actions.<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"The_Hydration_Mismatch_Nightmare\"><\/span>The Hydration Mismatch Nightmare<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If you&#8217;re using Next.js or any SSR (Server-Side Rendering) setup, you&#8217;ve likely seen the dreaded &#8220;Hydration failed because the initial UI does not match what was rendered on the server&#8221; error. This usually happens because you&#8217;re using something like <code>window.innerWidth<\/code> or <code>new Date()<\/code> inside your render function. The server renders one thing (where <code>window<\/code> doesn&#8217;t exist), and the client renders another.<\/p>\n<p>The fix isn&#8217;t to just suppress the warning. The fix is to ensure that the first render on the client matches the server exactly. Use <code>useEffect<\/code> to trigger any client-only logic <em>after<\/em> the initial mount.<\/p>\n<pre><code>const [isClient, setIsClient] = useState(false);\n\nuseEffect(() => {\n  setIsClient(true);\n}, []);\n\nif (!isClient) return &lt;LoadingSkeleton \/&gt;;\n\nreturn &lt;ClientOnlyComponent \/&gt;;\n<\/code><\/pre>\n<p>This pattern is ugly, but it&#8217;s the only way to prevent the &#8220;Flicker of Death&#8221; where the page layout jumps around as the client-side JS kicks in. As an SRE, I look at hydration errors as a sign of a brittle frontend. If the app can&#8217;t even agree on what time it is, how can I trust it to handle a complex checkout state?<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Data_Fetching_The_Stripe_Example\"><\/span>Data Fetching: The Stripe Example<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s look at a real-world scenario. You need to fetch a list of customers from <code>api.stripe.com\/v1\/customers<\/code> and display them in a table. The naive way is to use <code>useState<\/code> and <code>useEffect<\/code>. The <strong>react best<\/strong> way is to use a dedicated data-fetching library. Here is why:<\/p>\n<ol>\n<li><strong>Race Conditions:<\/strong> If a user clicks &#8220;Refresh&#8221; twice quickly, two API calls are fired. If the first one finishes <em>after<\/em> the second one, your UI will show stale data. TanStack Query handles this by canceling the previous request.<\/li>\n<li><strong>Caching:<\/strong> Why fetch the same data every time the user navigates back to the page? Cache it for 5 minutes.<\/li>\n<li><strong>Error Boundaries:<\/strong> What happens if the Stripe API returns a 503? Your whole app shouldn&#8217;t crash. You should catch that error at the component level.<\/li>\n<\/ol>\n<pre><code>\/\/ src\/features\/customers\/api\/getCustomers.ts\nimport { useQuery } from '@tanstack\/react-query';\n\nexport const useCustomers = () => {\n  return useQuery({\n    queryKey: ['customers'],\n    queryFn: async () => {\n      const response = await fetch('https:\/\/api.stripe.com\/v1\/customers', {\n        headers: { 'Authorization': `Bearer ${process.env.STRIPE_KEY}` }\n      });\n      if (!response.ok) throw new Error('Network response was not ok');\n      return response.json();\n    },\n    staleTime: 1000 * 60 * 5, \/\/ 5 minutes\n  });\n};\n<\/code><\/pre>\n<p>By abstracting the API call into a custom hook using a real library, you&#8217;ve solved caching, error handling, and loading states in about 15 lines of code. This is how you build systems that don&#8217;t break. You lean on battle-tested libraries instead of trying to reinvent the wheel with <code>useEffect<\/code> and <code>fetch<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_%E2%80%9CGod_Component%E2%80%9D_Anti-Pattern\"><\/span>The &#8220;God Component&#8221; Anti-Pattern<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We\u2019ve all seen it. The <code>Dashboard.tsx<\/code> file that is 2,500 lines long, takes 40 props, and has 15 different <code>useState<\/code> hooks. It\u2019s a &#8220;God Component.&#8221; It does everything, and therefore, it is impossible to change without breaking everything else. If you find yourself passing a prop down through five layers of components just to reach a button, you need to rethink your architecture.<\/p>\n<p>Instead of passing props, use <strong>Component Composition<\/strong>. Instead of a <code>Layout<\/code> component that takes <code>user<\/code>, <code>settings<\/code>, <code>notifications<\/code>, and <code>content<\/code> as props, make a <code>Layout<\/code> that takes <code>children<\/code>.<\/p>\n<pre><code>\/\/ Bad: Configuration-heavy\n&lt;PageHeader \n  title=\"Settings\" \n  showBackButton={true} \n  onBackClick={handleBack} \n  user={user} \n\/&gt;\n\n\/\/ Good: Composition-heavy\n&lt;PageHeader&gt;\n  &lt;BackButton onClick={handleBack} \/&gt;\n  &lt;Title&gt;Settings&lt;\/Title&gt;\n  &lt;UserAvatar user={user} \/&gt;\n&lt;\/PageHeader&gt;\n<\/code><\/pre>\n<p>Composition makes your components more flexible. If you suddenly need to add a &#8220;Search&#8221; bar to the header, you don&#8217;t have to modify the <code>PageHeader<\/code> component and add a <code>showSearchBar<\/code> prop. You just drop the <code>SearchBar<\/code> component inside the <code>PageHeader<\/code> tags. This is the Open-Closed Principle in action: components should be open for extension but closed for modification.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Observability_The_SREs_View_of_React\"><\/span>Observability: The SRE&#8217;s View of React<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>As an SRE, I don&#8217;t care how pretty your code is. I care if I can debug it when it breaks. Most React apps are black boxes. When a user says &#8220;the checkout button didn&#8217;t work,&#8221; we have no idea why. We need observability in the frontend just as much as we need it in the backend.<\/p>\n<ul>\n<li><strong>Error Boundaries:<\/strong> Wrap every major feature in an Error Boundary. If the &#8220;Recommendations&#8221; widget crashes, it shouldn&#8217;t take down the entire &#8220;Product Detail&#8221; page. Show a fallback UI and log the error to Sentry.<\/li>\n<li><strong>Custom Logging:<\/strong> Don&#8217;t just <code>console.error<\/code>. Use a structured logger that includes the component name, the user ID, and the state of the app when the error occurred.<\/li>\n<li><strong>Performance Monitoring:<\/strong> Use the <code>web-vitals<\/code> library to track LCP (Largest Contentful Paint) and CLS (Cumulative Layout Shift). Send this data to your monitoring tool (Datadog, New Relic, etc.).<\/li>\n<\/ul>\n<blockquote><p>\n  Pro-tip: Set up a &#8220;Dead Man&#8217;s Switch&#8221; for your frontend. If the main bundle fails to load or the root component fails to mount, have a tiny, inline script in <code>index.html<\/code> that sends a ping to your alerting system. Sometimes the app is so broken it can&#8217;t even report its own errors.\n<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"The_Final_Word_on_%E2%80%9CReact_Best%E2%80%9D\"><\/span>The Final Word on &#8220;React Best&#8221;<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The <strong>react best<\/strong> practices aren&#8217;t about using the latest experimental features or the trendiest styling library. They are about managing complexity. React makes it very easy to build something quickly, but it makes it very hard to build something that lasts. Every line of code you write is a liability. Every hook you add is a potential bug. Every library you install is a security vulnerability and a bundle-size tax.<\/p>\n<p>Stop trying to be clever. Stop trying to make your code &#8220;elegant.&#8221; Build boring, predictable, and explicit components. Use local state. Use URL params. Use TanStack Query. Wrap things in Error Boundaries. And for the love of all that is holy, stop using <code>useEffect<\/code> for things that aren&#8217;t side effects. Your SREs will thank you, and your users\u2014who are probably on a 3G connection with a $100 Android phone\u2014will actually be able to use your app.<\/p>\n<p>If you can&#8217;t explain how a component works to a junior dev in 30 seconds, it&#8217;s too complex. Delete it and start over.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Related_Articles\"><\/span>Related Articles<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Explore more insights and best practices:<\/p>\n<ul>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/power-saving-dark-mode-in-whatsapp\/\">Power Saving Dark Mode In Whatsapp<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/what-is-a-docker-container-a-complete-guide-for-beginners\/\">What Is A Docker Container A Complete Guide For Beginners<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/aws-ai-guide-build-and-scale-smarter-applications\/\">Aws Ai Guide Build And Scale Smarter Applications<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>React is Not a Framework, It\u2019s a Debt Generator (And How to Stop the Bleeding) Three years ago, I was paged at 2:14 AM on a Tuesday. Our main logistics dashboard, the one the warehouse teams use to track every single shipment across the Atlantic, had turned into a space heater. The browser was consuming &#8230; <a title=\"10 React Best Practices for Writing Cleaner Code in 2024\" class=\"read-more\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\" aria-label=\"Read more  on 10 React Best Practices for Writing Cleaner Code in 2024\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4812","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>10 React Best Practices for Writing Cleaner Code in 2024 - ITSupportWale<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"10 React Best Practices for Writing Cleaner Code in 2024 - ITSupportWale\" \/>\n<meta property=\"og:description\" content=\"React is Not a Framework, It\u2019s a Debt Generator (And How to Stop the Bleeding) Three years ago, I was paged at 2:14 AM on a Tuesday. Our main logistics dashboard, the one the warehouse teams use to track every single shipment across the Atlantic, had turned into a space heater. The browser was consuming ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\" \/>\n<meta property=\"og:site_name\" content=\"ITSupportWale\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\" \/>\n<meta property=\"article:published_time\" content=\"2026-06-10T18:11:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Techie\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Techie\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\"},\"author\":{\"name\":\"Techie\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\"},\"headline\":\"10 React Best Practices for Writing Cleaner Code in 2024\",\"datePublished\":\"2026-06-10T18:11:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\"},\"wordCount\":2431,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\",\"name\":\"10 React Best Practices for Writing Cleaner Code in 2024 - ITSupportWale\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\"},\"datePublished\":\"2026-06-10T18:11:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/itsupportwale.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"10 React Best Practices for Writing Cleaner Code in 2024\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"name\":\"ITSupportWale\",\"description\":\"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\",\"name\":\"itsupportwale\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"contentUrl\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"width\":1119,\"height\":144,\"caption\":\"itsupportwale\"},\"image\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\",\"name\":\"Techie\",\"sameAs\":[\"https:\/\/itsupportwale.com\",\"iswblogadmin\"],\"url\":\"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"10 React Best Practices for Writing Cleaner Code in 2024 - ITSupportWale","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/","og_locale":"en_US","og_type":"article","og_title":"10 React Best Practices for Writing Cleaner Code in 2024 - ITSupportWale","og_description":"React is Not a Framework, It\u2019s a Debt Generator (And How to Stop the Bleeding) Three years ago, I was paged at 2:14 AM on a Tuesday. Our main logistics dashboard, the one the warehouse teams use to track every single shipment across the Atlantic, had turned into a space heater. The browser was consuming ... Read more","og_url":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/","og_site_name":"ITSupportWale","article_publisher":"https:\/\/www.facebook.com\/Itsupportwale-298547177495978","article_published_time":"2026-06-10T18:11:43+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png","type":"image\/png"}],"author":"Techie","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Techie","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#article","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/"},"author":{"name":"Techie","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d"},"headline":"10 React Best Practices for Writing Cleaner Code in 2024","datePublished":"2026-06-10T18:11:43+00:00","mainEntityOfPage":{"@id":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/"},"wordCount":2431,"commentCount":0,"publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/","url":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/","name":"10 React Best Practices for Writing Cleaner Code in 2024 - ITSupportWale","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/#website"},"datePublished":"2026-06-10T18:11:43+00:00","breadcrumb":{"@id":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/itsupportwale.com\/blog\/10-react-best-practices-for-writing-cleaner-code-in-2024\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/itsupportwale.com\/blog\/"},{"@type":"ListItem","position":2,"name":"10 React Best Practices for Writing Cleaner Code in 2024"}]},{"@type":"WebSite","@id":"https:\/\/itsupportwale.com\/blog\/#website","url":"https:\/\/itsupportwale.com\/blog\/","name":"ITSupportWale","description":"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides","publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/itsupportwale.com\/blog\/#organization","name":"itsupportwale","url":"https:\/\/itsupportwale.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","contentUrl":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","width":1119,"height":144,"caption":"itsupportwale"},"image":{"@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Itsupportwale-298547177495978"]},{"@type":"Person","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d","name":"Techie","sameAs":["https:\/\/itsupportwale.com","iswblogadmin"],"url":"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4812","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/comments?post=4812"}],"version-history":[{"count":0,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4812\/revisions"}],"wp:attachment":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/media?parent=4812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/categories?post=4812"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/tags?post=4812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}