{"id":"09djnxiul7a3ald","title":"State Colocation vs Global Store for Content Sites","slug":"state-colocation-vs-global-store","summary":"Grabbing a global store to duck prop drilling usually backfires, triggering massive re-renders and making debugging a forensic chore.  Centralized state…","imageUrl":"https://briancrabtree.me/images/journal-state-colocation-vs-global-store.webp","category":"React","date":"2026-01-06T18:00:00.000Z","featured":false,"likes":42,"author":"Brian Crabtree","content":"<h2>When State Gets Messy</h2>\n\n<p>Every React project eventually hits the state management wall. You start simple with local component state, but then data needs to be shared across a dozen components, often seemingly unrelated ones. That's when the core architectural question of state colocation vs global store in React pops up, and how you answer it dictates a lot about your future.</p>\n\n<p>On content-heavy sites, where data fetches and display logic are spread across many distinct page sections, this dilemma is amplified. Developers often jump straight to the easiest solution they see, without fully considering the long-term impact on the codebase or user experience.</p>\n\n<p>The wrong decision here can lead to a tangled mess of prop drilling or, conversely, a global store that triggers unnecessary re-renders across your entire application. Both outcomes slow down development and user interaction, making future changes painful and risky.</p>\n\n<pre><code>// Prefer local state until two distant branches need the same data\nconst [likes, setLikes] = useState(post.likes);</code></pre>\n\n<h2>The Global Store Trap</h2>\n\n<p>It's tempting to reach for a global store solution. Tools like Redux, Zustand, or even a sprawling React Context provider promise universal access to data, simplifying what initially looks like complex prop-drilling scenarios. For new developers especially, this feels like an elegant shortcut to shared data.</p>\n\n<p>The appeal is clear: put everything important in one place, and any component can grab what it needs without passing props down many layers. This perceived simplicity can get a new feature out the door quickly, making the initial build feel productive and straightforward.</p>\n\n<p>However, that convenience often hides significant downstream costs. While useful for truly global application concerns, treating every piece of shared data as a global concern leads to a system where everything is interconnected, making changes ripple unpredictably.</p>\n\n<h2>The Cost of Centralization</h2>\n\n<p>The biggest hit from over-reliance on a global store is often performance. If a large segment of your application listens to a global store, every small change to that state can trigger a cascade of unnecessary re-renders across the component tree. This is especially problematic on content sites with many interactive elements or frequently updating data.</p>\n\n<p>Debugging also becomes a nightmare. When a component re-renders unexpectedly, tracking down the exact state change that caused it within a vast global store can be a forensic exercise. It's hard to reason about data flow when any part of the application can modify shared state at any time.</p>\n\n<p>This tight coupling and lack of clear ownership make refactoring terrifying. You touch one piece of global state, and suddenly unrelated components start breaking. What seemed simple initially evolves into a maintenance burden that stifles development velocity over time.</p>\n\n<h2>The Power of Colocation</h2>\n\n<p>My default approach now is state colocation. This means keeping state as close as possible to the components that actually use it and manage its lifecycle. It's about letting components own their specific data and logic, only elevating state when strictly necessary for truly shared functionality.</p>\n\n<p>The benefits are immediate: improved clarity, reduced re-renders, and far easier debugging. When state lives with its component, you know exactly where to look for changes and what components will be affected. This drastically simplifies understanding and modifying component behavior.</p>\n\n<p>For content sites, this often means components fetch and manage their own article comments, rating statistics, or localized UI elements. Each module operates with greater autonomy, leading to a more robust and predictable application structure.</p>\n\n<h2>React Context and Scope</h2>\n\n<p>React Context is often lumped in with global state solutions, but it's more nuanced. While it can act like a global store if you put your entire application state in one provider, its true power lies in providing scoped state. It's an excellent tool for avoiding prop drilling within a specific subtree.</p>\n\n<p>I use Context for things that are shared across a distinct section of the UI, but not the entire application. For instance, an `ArticleProvider` might manage state related to the current article, like its viewing mode or comment status. This keeps that state localized to the article components, separate from the rest of the site.</p>\n\n<p>This approach prevents the blanket re-renders a truly global store might cause, and keeps concerns cleanly separated. It's a precise scalpel, not a blunt instrument, for managing state when data needs to traverse a few component levels without affecting everything.</p>\n\n<h2>Strategic Global State</h2>\n\n<p>There absolutely are scenarios where a global store makes sense. Truly application-wide concerns like user authentication status, site-wide theme preferences, or global navigation data are good candidates. These are pieces of data that genuinely impact the entire user experience, no matter where they are on the site.</p>\n\n<p>My criteria for reaching for a global state manager are strict: is this data genuinely needed by almost every part of the application, or by disparate, unconnected parts that would require significant prop drilling otherwise? For typical react state management content site challenges, the answer is often no.</p>\n\n<p>The decision balances convenience with performance and maintainability. Opt for a global store only when the overhead of prop drilling or many local contexts genuinely outweighs the complexity and potential performance costs of centralizing the data. If you're digging into performance, check out my post on <a href=\"/journal/react-spa-overhead-real-cost/\">React SPA Overhead: The Real Cost Beyond Hello World</a>.</p>\n\n<h2>What I do next</h2>\n\n<p>My default now is to keep state as local as possible. I start with `useState` and `useReducer` within the component, and only elevate state if multiple siblings or direct parent/child components need to share it. If it's a specific subtree concern, I consider a scoped React Context.</p>\n\n<p>I rarely reach for a dedicated global state library unless the application's complexity clearly demands it, and even then, I segment the global store carefully. Simple, isolated state management generally leads to faster performance and fewer headaches on content-heavy sites.</p>\n\n<p>Prioritize clear ownership and predictable data flow over perceived shortcuts. That means embracing colocation as the default, and using global state only for truly global, non-negotiable application concerns. It builds a more robust, performant application, and that’s what matters. For a related angle I keep coming back to, see <a href=\"/journal/react-spa-overhead-real-cost/\">React SPA Overhead: The Real Cost Beyond Hello World</a>.</p>","tags":["state-management","react","architecture"],"views":106}