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 17 of the Advanced React: Performance, Architecture & Patterns course
ReactJune 27, 20264 min read

Mastering Control Props in React for Flexible Component APIs

Learn how to implement Control Props to build flexible React components that bridge internal state management with external control via unidirectional data flow.

ReactComponent PatternsAPI DesignState ManagementControlled Componentsjavascriptfrontend

Previously in this course, we explored designing compound components to create expressive, modular UIs. While compound components solve the problem of structural coupling, they often require a way to synchronize state between the library consumer and the component's internal logic. This is where the Control Props pattern becomes essential.

Understanding Control Props from First Principles

In React, a "controlled" component is one where the data flow is dictated by props rather than internal state. Think of standard <input /> elements: if you pass value and onChange, the input is controlled. If you don't, it manages its own state internally.

The Control Props pattern allows your custom components to behave exactly like native inputs. It provides a "power user" API: by default, the component is self-contained and easy to use (uncontrolled), but if a consumer provides a value prop, the component yields control to the parent (controlled).

To implement this, you must treat your internal state as a fallback, ensuring that the source of truth is always the external prop when provided.

Implementing a Controlled Toggle Component

Let’s build a Toggle component. We want it to be simple to use by default, but allow parent components to force a state change—for example, if a "Reset" button needs to flip the toggle back to false.

JSX
import React, { useState, useEffect } from CE9178">'react';

const Toggle = ({ on, onChange, defaultOn = false }) => {
  // 1. Determine if we are in "controlled" mode
  const isControlled = on !== undefined;

  // 2. Internal state for uncontrolled mode
  const [internalOn, setInternalOn] = useState(defaultOn);

  // 3. The source of truth
  const state = isControlled ? on : internalOn;

  const toggle = () => {
    const nextState = !state;
    // 4. Notify the parent if in controlled mode, 
    // otherwise update internal state
    if (!isControlled) {
      setInternalOn(nextState);
    }
    onChange?.(nextState);
  };

  return (
    <button onClick={toggle}>
      {state ? CE9178">'ON' : CE9178">'OFF'}
    </button>
  );
};

Why this works:

  • Unidirectional Data Flow: The state variable acts as a computed property. We never modify props directly; we only communicate intent via onChange.
  • Flexible API: The user can choose to ignore the on prop (uncontrolled) or provide it to synchronize the toggle with their own complex state (controlled).
  • onChange execution: We execute onChange regardless of the mode, allowing the parent to react to interactions even when they aren't explicitly controlling the state.

Hands-on Exercise: Adding onReset

In our current project—the large-scale dashboard we've been refactoring—we have a filter panel. Modify the Toggle component above to accept an optional onReset prop. When a reset occurs, the component should update its internal state to the defaultOn value even if it is currently in controlled mode.

Hint: Use a useEffect hook to sync defaultOn if the component is uncontrolled, or simply provide a public method via useImperativeHandle if you need to trigger an external reset.

Common Pitfalls

  1. Ignoring the undefined check: Never rely on a truthy/falsy check for props like value or on. 0 or false are valid values. Always check prop !== undefined.
  2. Double-updating: A common bug involves updating both internalOn and calling onChange in a way that causes the parent to re-render and pass the same value back, leading to unnecessary cycles. Always keep your conditional logic clean: if isControlled, setInternalOn is never called.
  3. Missing onChange: If you provide a controlled component, failing to provide an onChange handler essentially makes your component read-only. Always provide a warning or ensure your internal logic handles the absence of the handler gracefully (as shown with onChange?.()).

Summary of State Strategies

PatternSource of TruthBest For
UncontrolledInternal useStateSimple, self-contained UI
ControlledParent stateSyncing across components
Control PropsHybrid (Prop > State)Reusable library components

By implementing Control Props, you move your components from "black boxes" that hide their state to "collaborative primitives" that integrate seamlessly into any application architecture. This is a foundational step toward building the headless UI architectures we will discuss in the next lesson.

Up next

We will take the lessons learned here and apply them to Headless UI Architectures, decoupling our state management logic entirely from the DOM elements to create truly reusable, accessible primitives.

Previous lessonThe Render Props PatternNext lesson Headless UI Architectures
Back to Blog

Similar Posts

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.

Read more
ReactJune 26, 20264 min read

Managing Global Modals: A Scalable Pattern for React UI

Stop prop-drilling modal visibility. Learn to build a global modal system using Context API and state to trigger UI overlays from anywhere in your app.

Part of the course

Advanced React: Performance, Architecture & Patterns

advanced · Lesson 17 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 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
  • 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