React Native Flow

← Retour au blog

March 30, 2026·10 min read

Styling approaches: pick one your team will ship

Consistency beats fashion. Whether you use plain StyleSheet, a theme object, or utility classes, the win is everyone naming things the same way and dark mode not being an afterthought. The best system is the one new contributors can grep and follow in code review.

Design tokens

Colors, spacing, and type scales should live in one module. Screens import tokens, not magic numbers scattered everywhere.

Document how to add a new semantic color (“danger”, “success”).

Dark mode

Prefer semantic names (`surface`, `textPrimary`) over raw hex in components. Test components in both themes in Storybook or a sandbox screen.

System theme changes should respect user override.

Avoid mixing three systems

Migrating styling approaches mid-project is expensive. If you must, draw a boundary: new code uses X, old code stays until touched.

Performance: some runtime CSS-in-JS patterns cost more than StyleSheet; profile hot screens.

How to evaluate a new styling tool

Check: bundle impact, TypeScript story, how it plays with Fast Refresh, and whether designers can map Figma tokens to code without bespoke scripts. Pilot on one non-critical screen before you rewrite navigation.

If only one person understands the abstraction, it is not ready for the whole app.

Design tokens as source of truth

Centralize colors, spacing, typography scales, and radii. Name tokens semantically—`surfaceElevated` not `gray12`. Document how to add tokens—avoid one-off hex proliferation. Sync with design tools when possible to reduce drift.

Dark mode strategy

Semantic tokens adapt better than raw palette swaps. Test components in both modes early—retrofitting dark mode late is painful. Respect system theme changes and user overrides consistently. Watch contrast ratios for accessibility certification.

Choosing StyleSheet, CSS-in-JS, or utilities

StyleSheet is fast and simple. Runtime CSS-in-JS can cost performance on hot paths—profile. Utility approaches speed iteration but need discipline to avoid unreadable class strings. Pick one primary system; mixing increases cognitive load.

Migration patterns

Strangler patterns work: new screens use new system, old screens migrate opportunistically. Codemods help rename tokens. Communicate timelines to avoid half-migrated screens confusing designers. Snapshot visual tests catch accidental theme breaks.

Component API design

Expose style extension points carefully—too open invites inconsistency. Document variants (`primary`, `danger`) versus free-form style overrides. Keep spacing props aligned with token scales to prevent magic numbers.

Performance considerations

Avoid inline style object churn in hot renders. Memoize expensive style computations. Large shadows and blurs cost GPU—use sparingly on scrolling surfaces. Profile after visual redesigns—pretty can be slow.

Governance

Establish a styling working group for token updates. Review third-party components for theme compatibility. Revisit choices after major RN upgrades—layout engines evolve. Consistency beats novelty for mature apps.

Shipping and reliability habits (1)

Storage is not a database. AsyncStorage and MMKV excel at key-value preferences; SQLite or remote APIs belong elsewhere for relational data. Migrations should be incremental, logged, and non-blocking for UI. Secure tokens need secure storage when your model demands it—speed is not a substitute for correctness on auth material.

WebViews are untrusted browsers inside your app. Validate `postMessage` payloads, lock navigation to expected hosts, and prefer system-browser auth flows when OAuth security demands it. Third-party JavaScript can change without your deploy—treat XSS in web as bridge compromise risk. Clear storage on logout and rate-limit message handlers.

Platform differences worth rehearsing (2)

JWT and session refresh flows need single-flight refresh, clear logout semantics, and secure storage for refresh tokens when appropriate. Parallel 401s should not stampede refresh endpoints. Clock skew and biometrics policies belong in explicit product decisions, not accidental implementation details.

In-app purchases require server validation, restore flows, and support tooling that respects privacy. Sandbox quirks are normal—budget QA time. Subscriptions interact with family sharing, regional pricing, and refunds; engineering must stay aligned with finance and legal narratives users see in receipts.

Security, privacy, and data handling (3)

Background execution policies change with OS updates—revalidate after major iOS and Android releases. Misused background modes invite rejection. Persist user work frequently; the OS can kill you anytime after backgrounding. Uploads and timers should tolerate pause and resume without corrupting state.

Design tokens and semantic colors make dark mode and rebrands feasible. Mixing three styling systems doubles migration cost—pick a primary approach and draw boundaries. Runtime CSS-in-JS can cost frame time on hot screens—profile before adopting wholesale.

Performance and measurement discipline (4)

Performance work should start with measurement, not instinct. Watch JS thread versus UI thread separately; they bottleneck differently. Lists, images, and animations dominate most regressions—optimize those before micro-optimizing pure functions. Hermes, JSC, and bridge internals evolve; re-profile after every major upgrade instead of trusting last year’s numbers. Battery and thermal throttling on mid devices reveal issues flagship phones hide.

Security and privacy expectations move faster than roadmaps. Treat analytics, crash, and attribution SDKs as part of your threat model: initialize them deliberately, document data flows, and verify ‘off’ truly stops network calls. Client-side secrets are public secrets—anything shipped in an APK or IPA should be assumed extractable. Pair mobile changes with backend policies so authorization remains consistent across platforms.

Team process and long-term maintenance (5)

Images and maps look simple in mocks and expensive in production. Decode sizes should match display sizes; static map thumbnails are not interchangeable with interactive MapView gestures. Quotas, API keys, and offline behavior need explicit fallbacks—addresses as text, retry buttons, and calm error copy. Monitor vendor dashboards for spikes that indicate bugs or abuse.

Error boundaries catch render failures, not native crashes or async mistakes. Pair them with platform crash reporting and structured client logs. Fallback UI should include build identifiers and humane copy—never raw stack traces for end users. Test fallbacks with screen readers; a broken error screen is still broken UX.

Shipping and reliability habits (6)

FlatList performance is configuration as much as code. Stable keys, reasonable `windowSize`, and memoized rows beat switching to a different list primitive blindly. Nested virtualized lists are a last resort—redesign first. Profile with production-like data volumes; dev placeholders lie.

Splash screens and launch gates should reflect honest readiness: fonts, theme, session, critical remote config—not every SDK under the sun. Infinite splash is worse than a slightly longer branded hold. Match native and JS background colors to avoid flashes; respect reduced motion for animations.

Platform differences worth rehearsing (7)

Analytics schema governance prevents warehouse disasters: version events, avoid high-cardinality strings, and align names across iOS, Android, and web. Consent gating must stop network calls, not just UI. Separate dev and prod projects to avoid polluting dashboards.

Testing onboarding changes with funnel metrics beats debating opinions. Segment by acquisition channel and platform; back behavior differs. Skip paths must be genuine—dark patterns may win short metrics and destroy brand trust. Localization length tests prevent clipped CTAs in verbose languages.

Security, privacy, and data handling (8)

Helper modules concentrate glue code—storage, navigation, permissions—so screens stay readable. Split helpers by topic before files become merge-conflict magnets, and document each module’s contract. Good helpers answer ‘where do we save tokens?’ in one glance—not ‘ask Sarah.’

Shipping React Native features is less about any single API and more about the system around it: typed boundaries, predictable navigation, and telemetry that tells you what broke in production. Prefer boring, explicit modules over clever metaprogramming that the next hire cannot grep. When platform vendors change behavior in point releases, your defense is automated smoke tests on real devices and a short internal changelog of native assumptions you rely on.

Performance and measurement discipline (9)

Deep links are a cross-team system: marketing URLs, hosted association files, entitlements, router params, and analytics query preservation. Debug with structured logging of raw URLs (scrub secrets) and reproduce cold-start races with auth hydration. Staging and production should be obviously separated—accidentally opening prod from a QA link erodes trust and pollutes data.

Push notifications walk a line between helpful and intrusive. Prime users with context, respect notification channels on Android, and measure opt-outs after campaigns—spikes mean copy or frequency problems. Payload design affects background behavior; test killed and locked-device states. Tokens belong server-side with rotation strategies; never treat the client as authoritative for subscription state.

Team process and long-term maintenance (10)

Keyboard and form UX separate polished apps from ‘works on desktop simulators.’ Platform differences in soft input modes matter; test smallest phones and Android gesture navigation. Primary actions must remain reachable when the keyboard is visible—scroll containers and keyboard controllers exist because this problem is universal.

Type-safe navigation pays off when routes multiply. Keep param lists near navigators, validate external URLs, and avoid serializing non-JSON-safe values through params. Renaming routes is a cross-cutting change—update analytics, push payloads, and E2E selectors in the same release train.

Shipping and reliability habits (11)

Error boundaries catch render failures, not native crashes or async mistakes. Pair them with platform crash reporting and structured client logs. Fallback UI should include build identifiers and humane copy—never raw stack traces for end users. Test fallbacks with screen readers; a broken error screen is still broken UX.

Storage is not a database. AsyncStorage and MMKV excel at key-value preferences; SQLite or remote APIs belong elsewhere for relational data. Migrations should be incremental, logged, and non-blocking for UI. Secure tokens need secure storage when your model demands it—speed is not a substitute for correctness on auth material.

Platform differences worth rehearsing (12)

Type-safe navigation pays off when routes multiply. Keep param lists near navigators, validate external URLs, and avoid serializing non-JSON-safe values through params. Renaming routes is a cross-cutting change—update analytics, push payloads, and E2E selectors in the same release train.

FlatList performance is configuration as much as code. Stable keys, reasonable `windowSize`, and memoized rows beat switching to a different list primitive blindly. Nested virtualized lists are a last resort—redesign first. Profile with production-like data volumes; dev placeholders lie.

Security, privacy, and data handling (13)

Expo SDK upgrades are integration projects: `expo doctor`, aligned community packages, regenerated native projects, and device smoke tests for camera, push, and IAP. Freeze unrelated native refactors during the upgrade window and keep rollback paths hot. Document surprises for the next upgrade while memory is fresh.

Hermes versus JSC is not a lifestyle choice—profile your app. Hermes usually wins on startup; some libraries still assume JSC quirks. Engine toggles are not substitutes for fixing quadratic renders in your own code. Upgrade notes matter: Intl support and debugging tooling evolve.

Performance and measurement discipline (14)

Design tokens and semantic colors make dark mode and rebrands feasible. Mixing three styling systems doubles migration cost—pick a primary approach and draw boundaries. Runtime CSS-in-JS can cost frame time on hot screens—profile before adopting wholesale.

ScrollView versus FlatList is a data-volume question. Small static content belongs in ScrollView; long feeds belong in virtualized lists. Nested scrollables need explicit height contracts—redesign beats fighting physics. Document intentional choices so future refactors do not ‘optimize’ blindly.

Team process and long-term maintenance (15)

Shipping React Native features is less about any single API and more about the system around it: typed boundaries, predictable navigation, and telemetry that tells you what broke in production. Prefer boring, explicit modules over clever metaprogramming that the next hire cannot grep. When platform vendors change behavior in point releases, your defense is automated smoke tests on real devices and a short internal changelog of native assumptions you rely on.

Performance work should start with measurement, not instinct. Watch JS thread versus UI thread separately; they bottleneck differently. Lists, images, and animations dominate most regressions—optimize those before micro-optimizing pure functions. Hermes, JSC, and bridge internals evolve; re-profile after every major upgrade instead of trusting last year’s numbers. Battery and thermal throttling on mid devices reveal issues flagship phones hide.

Shipping and reliability habits (16)

Native modules are product decisions disguised as engineering tasks. You inherit Xcode and Gradle upgrades, store review scrutiny, and security obligations. Prefer maintained Expo modules and config plugins before writing JNI or Swift glue from scratch. When you must go native, budget pairing time with platform specialists and write runbooks for on-call—crashes in native code bypass many JS safeguards.

Deep links are a cross-team system: marketing URLs, hosted association files, entitlements, router params, and analytics query preservation. Debug with structured logging of raw URLs (scrub secrets) and reproduce cold-start races with auth hydration. Staging and production should be obviously separated—accidentally opening prod from a QA link erodes trust and pollutes data.

Sponsorisé

Promo rapide