mediumEngineering Practices#83

Single Responsibility: component splitting

Prompt

Split this monolithic screen into three components: UserHeader (avatar + name), UserStats (followers + following), UserBio (description). Give each component narrow props — only the fields it renders.

Solution

function UserHeader({ avatar, name }) {
  return (
    <View style={{ flexDirection: 'row', alignItems: 'center' }}>
      <Image source={{ uri: avatar }} style={{ width: 48, height: 48, borderRadius: 24 }} />
      <Text style={{ fontSize: 18, fontWeight: 'bold', marginLeft: 12 }}>{name}</Text>
    </View>
  )
}

function UserStats({ followers, following }) {
  return (
    <View style={{ flexDirection: 'row', gap: 16 }}>
      <Text>{followers} followers</Text>
      <Text>{following} following</Text>
    </View>
  )
}

function UserBio({ bio }) {
  return <Text>{bio}</Text>
}

export default function UserProfile({ user }) {
  return (
    <View>
      <UserHeader avatar={user.avatar} name={user.name} />
      <UserStats followers={user.followers} following={user.following} />
      <UserBio bio={user.bio} />
    </View>
  )
}
Mentor's take

Single Responsibility for components means one reason to change per component: the header changes when identity display changes, stats when the metrics change, bio when the description treatment changes. The monolith forces every one of those changes through the same file — merge conflicts, wider review surface, and a component nobody can test in isolation.

The detail that separates a senior split from a cosmetic one is the props contract. Passing narrow props (avatar, name) instead of the whole user object does three things: the component's dependencies are visible in its signature; it's reusable anywhere you have a name and an avatar, not just where you have this exact User shape; and React.memo becomes effective, because primitive props compare cheaply while a fresh user object reference defeats memoization every render. Passing user everywhere is SRP theater — the coupling survives the split.

Worth naming the placement framework: SOLID governs how a class or component is designed; GRASP governs where a responsibility lives. This exercise is GRASP's Information Expert applied to UI — give the rendering responsibility to the component that holds exactly the data it needs.

Red flag: splitting purely by visual layout while threading the entire user object into every child — you've multiplied files without reducing coupling.

Say it: "I split by reason-to-change and keep props narrow — each child declares exactly the fields it renders, which is also what makes memoization actually work."