React · Component Patterns

Component Patterns Interview Questions
With Answers & Code Examples

4 carefully curated Component Patterns interview questions with working code examples and real interview gotchas.

Practice Interactively →← All Categories
4 questions0 beginner2 core2 advanced
Q1Core

What is the Compound Component pattern?

💡 Hint: Related components share implicit state via context — like <select> and <option> in HTML

Compound components work together, sharing state implicitly through context. The parent manages state; children access it without explicit prop passing.

const TabsContext = createContext(null);

function Tabs({ children, defaultTab }) {
  const [active, setActive] = useState(defaultTab);
  return (
    
      
{children}
); } function TabList({ children }) { return
{children}
; } function Tab({ id, children }) { const { active, setActive } = useContext(TabsContext); return ( ); } function TabPanel({ id, children }) { const { active } = useContext(TabsContext); return active === id ?
{children}
: null; } // Usage — clean, flexible, no prop drilling Profile Settings
💡 Good examples: Tabs, Accordion, Dropdown, Form with Field/Label/Error subcomponents. The key insight — the developer using the component controls the structure; the component controls the behavior.
Practice this question →
Q2Core

What is the Render Props pattern and when would you still use it?

💡 Hint: Pass a function as a prop that returns JSX — the component calls it with its internal state
// Render props — component shares state by calling a function prop
function MouseTracker({ render }) {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  return (
    
setPos({ x: e.clientX, y: e.clientY })}> {render(pos)} {/* caller decides what to render */}
); } // Usage (

Mouse at {x}, {y}

)} /> // children as a function (same pattern) {({ x, y }) => }

Render props vs custom hooks:

  • Custom hooks replaced most render prop use cases (simpler, less nesting)
  • Render props still shine when you need to inject JSX into a specific DOM location managed by the component
  • Libraries like React Table, Downshift, and Formik use render props for maximum flexibility
💡 If the render prop is just sharing state logic, refactor to a custom hook. If it's about rendering into a specific slot (like a virtualized list rendering each row), render props are still the right tool.
Practice this question →
Q3Advanced

What is the Provider pattern and how do you build a scalable context architecture?

💡 Hint: Separate state logic from context provision — custom hook for consumers, provider component for setup
// ─── auth-context.tsx ───────────────────────────────────────────────────────
type AuthContextValue = {
  user: User | null;
  login: (credentials: Credentials) => Promise;
  logout: () => void;
};

const AuthContext = createContext(null);

// Provider encapsulates all auth logic
export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState(null);

  const login = useCallback(async (creds) => {
    const user = await api.login(creds);
    setUser(user);
  }, []);

  const logout = useCallback(() => {
    api.logout();
    setUser(null);
  }, []);

  return (
    
      {children}
    
  );
}

// Custom hook — type-safe, error if used outside provider
export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be used within AuthProvider');
  return ctx;
}

// ─── app layout ──────────────────────────────────────────────────────────────

  
    
      
    
  
💡 The null-check in useAuth() is critical for DX — it gives a clear error message instead of a cryptic "cannot read property of undefined" when someone forgets the provider.
Practice this question →
Q4Advanced

What is the Container/Presentational pattern? Is it still relevant?

💡 Hint: Smart vs dumb components — data fetching separated from rendering; largely replaced by hooks but the principle remains

The pattern separates data concerns (fetching, state) from UI concerns (rendering, styling):

// ❌ Old way — explicit Container component
function UserListContainer() {
  const [users, setUsers] = useState([]);
  useEffect(() => { fetchUsers().then(setUsers); }, []);
  return ; // pass data down
}

function UserList({ users }) {
  return users.map(u => );
}

// ✅ Modern way — custom hook achieves the same separation
function useUsers() {
  return useQuery(['users'], fetchUsers);
}

// Presentational component stays the same
function UserList({ users }) {
  return users.map(u => );
}

// Consuming component — much simpler
function UsersPage() {
  const { data: users } = useUsers();
  return ;
}

Still relevant principles:

  • Keep components that render UI free of data-fetching — easier to test, reuse in Storybook
  • The separation now lives in custom hooks, not wrapper components
💡 The pattern's goal (separation of concerns) is still correct; the implementation changed. Hooks achieve it more elegantly without extra component nesting.
Practice this question →

Other React Interview Topics

Rendering StrategiesCore JSType SystemReact FundamentalsFunctionsMicrofrontendsGenericsAsync JSHooksObjectsMonorepoArrays'this' KeywordUtility TypesError HandlingModern JSBundle OptimizationPerformanceDOM & EventsState ManagementClasses & OOPCaching StrategiesAdvanced TypesAuthenticationReact RouterFormsAdvanced PatternsFrontend SecurityConcurrent ReactServer ComponentsTestingEcosystemNetwork OptimizationCore Web VitalsBrowser APIs

Ready to practice Component Patterns?

Get AI feedback on your answers, predict code output, and fix real bugs.

Start Free Practice →