Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

Subscribe to the newsletter

Get new articles and course lessons delivered to your inbox. No spam, unsubscribe anytime.

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 6 of the Advanced React: Performance, Architecture & Patterns course
ReactJune 27, 20264 min read

State Colocation Strategies: Optimizing React Component Architecture

Master State Colocation to stop unnecessary re-renders. Learn to move state as close as possible to its consumption point for high-performance React apps.

ReactPerformanceArchitecturePatternsState Managementjavascriptfrontend

Previously in this course, we covered Strategic use of React.memo: Advanced Component Optimization to prevent unnecessary re-renders. While React.memo is a powerful tool for memoizing expensive components, it is often a "band-aid" for poor state placement. In this lesson, we shift our focus to State Colocation, the architectural practice of moving state as close as possible to where it is actually consumed.

The Problem: Monolithic State Architecture

In many React codebases, developers fall into the trap of "lifting state up" by default. While centralizing state in a parent component seems cleaner, it creates a performance bottleneck: whenever that state updates, the entire subtree re-renders.

If you find yourself passing props through three or four layers of components that don't need them (prop drilling) just to satisfy a distant child, you have a colocation problem. This not only makes your code harder to maintain but also triggers unnecessary reconciliation across the entire component tree, as discussed in our Deep Dive into the Reconciliation Algorithm.

Identifying State for Colocation

The rule of thumb is simple: Keep state as close to its usage as possible. If a piece of state is only used by a single child component and its descendants, it has no business living in the parent.

Look for these signs that your state needs to be moved down:

  1. Prop Drilling: You are passing a state value through multiple levels of components that don't interact with it.
  2. "Heavy" Parents: A parent component is re-rendering frequently because of a state change that only affects a small leaf component.
  3. Context Bloat: You are using global state or context for data that is strictly local to a specific UI feature.

Worked Example: Refactoring a Dashboard

Imagine a Dashboard component that manages a searchQuery and a taskList. Currently, the Dashboard handles both, causing the entire dashboard to re-render whenever the user types in the search bar.

JSX
// BEFORE: Monolithic state placement
function Dashboard() {
  const [searchQuery, setSearchQuery] = useState(CE9178">'');
  const [tasks, setTasks] = useState([]);

  return (
    <div>
      <SearchBar value={searchQuery} onChange={setSearchQuery} />
      <TaskList tasks={tasks} filter={searchQuery} />
    </div>
  );
}

If SearchBar updates searchQuery on every keystroke, TaskList re-renders even if the list data hasn't changed. We can improve this by colocating the search state.

JSX
// AFTER: Granular local state
function SearchBar({ onSearch }) {
  const [query, setQuery] = useState(CE9178">'');
  
  const handleChange = (e) => {
    setQuery(e.target.value);
    onSearch(e.target.value);
  };

  return <input value={query} onChange={handleChange} />;
}

function Dashboard() {
  const [tasks, setTasks] = useState([]);

  return (
    <div>
      <SearchBar onSearch={/* handle filter logic */} />
      <TaskList tasks={tasks} />
    </div>
  );
}

By moving the query state into SearchBar, we isolate the re-renders. Typing in the search box now only triggers a re-render of SearchBar, not the Dashboard or the TaskList.

Hands-on Exercise

  1. Open your current project and identify a component that manages state for a sub-component.
  2. Use the React DevTools to record a profile session. Look for components that re-render even though their props didn't change (the "why did this render" feature).
  3. Identify one piece of state that is only used by a single child.
  4. Move that state from the parent into the child component.
  5. Verify with the Profiler that the parent no longer re-renders when that local state changes.

Common Pitfalls

  • Premature Optimization: Don't move state down if it needs to be shared by siblings. If two components need the same state, lifting it is correct.
  • Complex Synchronization: If you move state down but still need to access it from the parent, you might be tempted to use useImperativeHandle or complex refs. If the state is truly needed by the parent, keep it there.
  • Ignoring Component Composition: Sometimes the fix isn't moving state, but changing the component structure. Passing components as children to a parent can prevent the parent's re-renders from cascading down.

Recap

  • State Colocation is the practice of placing state at the lowest possible point in the component tree.
  • It minimizes the number of components affected by state updates, directly improving performance.
  • Always check if you are "lifting state" out of convenience rather than necessity.
  • Use the React Profiler to validate that your refactoring actually reduced the number of re-renders.

Up next, we will look at Optimizing Context Providers to ensure that when we do need to share state globally, we do it without triggering unnecessary re-renders across the app.

Previous lessonMastering useCallback and useMemoNext lesson Optimizing Context Providers
Back to Blog

Similar Posts

ReactJune 26, 20263 min read

Advanced Context Patterns: Scalable State for React Dashboards

Stop the "provider hell" and performance bottlenecks. Learn advanced context patterns to manage large-scale state trees and optimize your React architecture.

Read more
ReactJune 27, 20263 min read

Designing Compound Components: Advanced React Architecture Patterns

Master Compound Components in React to build flexible, intuitive UI APIs. Learn to share implicit state and enforce structure without the mess of prop drilling.

Part of the course

Advanced React: Performance, Architecture & Patterns

advanced · Lesson 6 of 47

  1. 1

    Deep Dive into the Reconciliation Algorithm

    4 min
  2. 2

    Profiling with React DevTools

    3 min
  3. 3

    Establishing Performance Budgets

    3 min
Read more
ReactJune 27, 20264 min read

Mastering Suspense for Data Fetching: A Declarative Approach

Stop managing manual boolean loading flags. Learn to implement Suspense boundaries to orchestrate data fetching and create seamless, declarative loading states.

Read more
  • 4

    Strategic use of React.memo

    3 min
  • 5

    Mastering useCallback and useMemo

    4 min
  • 6

    State Colocation Strategies

    4 min
  • 7

    Optimizing Context Providers

    4 min
  • 8

    Advanced Context Composition

    4 min
  • 9

    Eliminating Prop Drilling

    4 min
  • 10

    Introduction to Concurrent React

    4 min
  • 11

    Non-blocking UI with useTransition

    4 min
  • 12

    Handling Deferred Data with useDeferredValue

    3 min
  • 13

    Mastering Suspense for Data Fetching

    4 min
  • 14

    Streaming Server-Side Rendering

    3 min
  • 15

    Designing Compound Components

    3 min
  • 16

    The Render Props Pattern

    4 min
  • 17

    Implementing Control Props

    4 min
  • 18

    Headless UI Architectures

    3 min
  • 19

    Modular Directory Structures

    3 min
  • 20

    Refactoring Monolithic Components

    3 min
  • 21

    Optimistic UI Updates

    3 min
  • 22

    Advanced Cache Invalidation

    4 min
  • 23

    Handling Race Conditions

    4 min
  • 24

    Server-Client State Synchronization

    3 min
  • 25

    Route-level Code Splitting

    4 min
  • 26

    Offloading Tasks with Web Workers

    3 min
  • 27

    Advanced Error Boundaries

    3 min
  • 28

    Monitoring Production Performance

    4 min
  • 29

    Final Project Audit & Optimization

    Coming soon
  • 30

    Advanced Hook Patterns

    Coming soon
  • 31

    Managing Global State with Zustand/Redux

    Coming soon
  • 32

    Testing Performance-Critical Components

    Coming soon
  • 33

    Static Site Generation (SSG) Patterns

    Coming soon
  • 34

    Internationalization (i18n) Architecture

    Coming soon
  • 35

    Accessibility (a11y) in Advanced Components

    Coming soon
  • 36

    Managing Third-Party Integrations

    Coming soon
  • 37

    Advanced Form Handling

    Coming soon
  • 38

    Using Portals for UI Overlays

    Coming soon
  • 39

    Implementing Virtualized Lists

    Coming soon
  • 40

    Building Design System Primitives

    Coming soon
  • 41

    Managing Large-Scale Data Fetching

    Coming soon
  • 42

    Micro-Frontends with React

    Coming soon
  • 43

    Security Best Practices in React

    Coming soon
  • 44

    Advanced Ref Usage

    Coming soon
  • 45

    Memoization Pitfalls

    Coming soon
  • 46

    Mastering React Patterns for Scalability

    Coming soon
  • 47

    Advanced TypeScript with React

    Coming soon
  • View full course