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 Strategies →Core JS →Type System →React Fundamentals →Functions →Microfrontends →Generics →Async JS →Hooks →Objects →Monorepo →Arrays →'this' Keyword →Utility Types →Error Handling →Modern JS →Bundle Optimization →Performance →DOM & Events →State Management →Classes & OOP →Caching Strategies →Advanced Types →Authentication →React Router →Forms →Advanced Patterns →Frontend Security →Concurrent React →Server Components →Testing →Ecosystem →Network Optimization →Core Web Vitals →Browser APIs →

Ready to practice Component Patterns?

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

Start Free Practice →