mediumReact#41

Composition vs inheritance

Prompt

Create a Dialog component that uses composition — accept a "title" prop and "children" for the body content. Render a close button and the children.

Solution

function Dialog({ title, children, onClose }) {
  return (
    <View style={{ padding: 24, backgroundColor: 'white', borderRadius: 8 }}>
      <View style={{ flexDirection: 'row', justifyContent: 'space-between', marginBottom: 16 }}>
        <Text style={{ fontSize: 18, fontWeight: 'bold' }}>{title}</Text>
        <Button title="X" onPress={onClose} />
      </View>
      {children}
    </View>
  )
}
Mentor's take

React chose composition over inheritance deliberately: a component hierarchy built on extends couples every variant to a base class's internals, while composition keeps each component a black box configured entirely through its props. The React team's own guidance is that they've found no case where inheritance is the better tool — specialization is "a specific component rendering a generic one and configuring it with props."

The mechanics: children is just a prop — whatever sits between <Dialog> and </Dialog> arrives as props.children, and the Dialog renders it as an opaque slot. Dialog owns the chrome (padding, header row, close button); the caller owns the content. Neither knows the other's internals, which is what makes Dialog reusable for a confirm, a form, or an image preview without modification. Need multiple slots? Pass elements as named props (header, footer) — props can hold JSX like any other value.

The trade-off to name: composition pushes configuration to the call site, so a deeply configurable component can grow a wide prop surface. That's still cheaper than an inheritance tree, because each prop is an explicit contract instead of an implicit override.

Red flag: Reaching for a BaseDialog class with ConfirmDialog extends BaseDialog. In a React interview that signals fighting the framework — the idiomatic answer is a generic component specialized via props and children.

Say it: "children is just a prop, so containment is free — the component owns its chrome, callers own the content, and specialization happens with props, never with extends."