easyReact Native#23

Native module bridge (Platform.select)

Prompt

Use Platform.select to render a different component on iOS vs Android. On iOS show "iOS Button", on Android show "Android Button", default fallback to "Web Button".

Solution

const buttonText = Platform.select({
  ios: 'iOS Button',
  android: 'Android Button',
  default: 'Web Button',
})
return <Button title={buttonText} onPress={() => {}} />
Mentor's take

Platform.select is about keeping platform divergence declarative and in one place. The naive alternative — Platform.OS === 'ios' ? ... : ... ternaries scattered through render code — works, but each one is an ad-hoc branch a reviewer must re-derive, and chains break the moment web or a third platform appears. select reads as a table: every platform's value visible at a glance, default as the explicit catch-all for platforms you didn't enumerate (web, windows). It resolves once at execution, returns the matching value, and works for anything — strings, style objects, even components.

Knowing the escalation ladder is the senior part, because Platform.select is only the smallest tool:

  • A value differsPlatform.select (often inline in a StyleSheet, e.g. iOS shadow vs Android elevation).
  • A whole implementation differs → platform file extensions: Button.ios.tsx / Button.android.tsx, and Metro resolves the right file at bundle time — the other platform's code never ships in the bundle, unlike select, which carries all branches at runtime.
  • The capability itself differs → a native module or library boundary.

Red flag: sprinkling Platform.OS ternaries through every component. One or two are fine; a codebase full of them means divergence was never given a home — name file extensions as the structural fix.

Say it: "Platform.select keeps small divergences declarative with an explicit default; when a whole component diverges I switch to .ios/.android files so Metro resolves it at bundle time instead of branching at runtime."