pavel@portfolio:~$

$ ls -la ~/

pasha.petrovich98@gmail.comgithub.com/pavel-labslinkedin.com/in/pavel-software-anywhere
../blog
react-native-real-world-2026.mdx· 5 min read

React Native in 2026: what actually matters in real cross-platform apps

React Native is easy to start, but the hard part is not writing components. It is building a shared UI system that still feels native, works across platforms, and survives real product pressure.

#react-native#expo#mobile#architecture#cross-platform

React Native looks simple from the outside. You write components, you render them on mobile, and suddenly you have iOS and Android from one codebase. That is the marketing version. The real version is a bit more honest: React Native is great when you treat it like a shared product platform, not as if it magically removes all platform complexity.

The first mistake is thinking it is 'just React'

The biggest difference is that the UI is still native, but the app logic lives in a JavaScript runtime that is connected to platform APIs. That means a lot of problems are not React problems. They are platform problems: keyboard behavior, scroll gestures, safe areas, Android back navigation, camera permissions, file system access, app lifecycle, and differences in animation timing.

In real work, this means the architecture matters more than the initial speed. If you build a product as if both platforms are identical, you will hit the same issues later: inconsistent list scrolling, weird keyboard overlap, different gesture handling, and small but expensive release bugs.

import { Platform, KeyboardAvoidingView, ScrollView } from 'react-native'

export function LoginScreen() {
  const isAndroid = Platform.OS === 'android'

  return (
    <KeyboardAvoidingView behavior={isAndroid ? 'height' : 'padding'}>
      <ScrollView contentInsetAdjustmentBehavior={'automatic'} />
    </KeyboardAvoidingView>
  )
}

The real win is a shared design system, not just shared screens

The projects that work best are not the ones with the most shared screens. They are the ones with a solid shared UI layer: spacing scale, colors, typography tokens, button variants, cards, forms, modal patterns, and a clear set of primitive components. That is where cross-platform work becomes predictable.

In one of the apps I worked on, we built a white-label UI kit with theme tokens and reusable components. The product was not the same across clients, but the architecture was. That let us change brand colors, spacing, and some product-specific behavior without rewriting each feature. This is usually where the actual business value shows up: the product can scale without duplicating logic everywhere.

“The most important thing in React Native is not 'how fast can we build screens'. It is 'how much of the product can we share without losing native quality.'”

Cross-platform code is only 70-80% shared in practice

The hard truth is that a lot of the code can be shared, but not all of it. The product layer is usually shared. The navigation patterns are often shared. The state logic is often shared. The actual UI details are not always identical: iOS has different list behavior, Android has different back-stack patterns, and devices behave differently depending on keyboard, screen size, and OS version.

  • Shared domain logic and API contracts are easy to reuse and should be treated as first-class code.
  • Shared UI primitives are a huge win if they are designed well and kept consistent.
  • Platform-specific wrappers should be isolated, not scattered across the app.
  • Most product bugs are not caused by React itself — they are caused by ignoring platform differences.

State and data fetching need a clear boundary

It is tempting to put everything in screens. In real apps, that becomes unmaintainable fast. The better pattern is to keep screens as composition layers and move business logic to hooks, services, or a shared state layer. That makes it easier to test, easier to change, and easier to reuse across similar flows.

function useUserProfile() {
  const query = useQuery({
    queryKey: ['profile'],
    queryFn: fetchProfile,
  })

  return {
    profile: query.data,
    loading: query.isLoading,
    error: query.error,
  }
}

export function ProfileScreen() {
  const { profile, loading } = useUserProfile()
  return <ProfileContent profile={profile} loading={loading} />
}

Testing is more important than people expect

A cross-platform app is full of places where one platform quietly breaks the other. That is why testing matters so much. I spent a lot of time on Playwright-style checks and targeted mobile QA, because a UI that looks fine in one environment can still fail in another due to keyboard, focus, gestures, scroll, or layout edge cases.

This is also where Storybook or a component catalog helps. It gives you a stable way to test UI primitives, theme changes, and complex states without relying on whole app flows every time.

Expo is helpful, but it does not remove native work

Expo makes a lot of the setup and tooling easier. It is a great default for a product team. But it does not change the fact that some features need native modules, native config, or careful release management. The app still needs to be tested on real devices. The app still needs to be prepared for app store release. The app still needs to respect OS-level differences.

That is why I think the right mindset is not 'React Native removes native work.' It is 'React Native lets us share most of the business logic while still respecting the platform.' That is a much more realistic and useful way to approach mobile product delivery.

What I actually value most

  • A strong shared UI layer with tokens and reusable primitives.
  • A strict separation between shared logic and platform-specific code.
  • Testing and QA that includes real device behavior, not just a happy-path simulator.
  • Comfort with the fact that iOS and Android are not the same product, even when they share code.

React Native is not magic. It is a really good way to build a product if you respect the platform. The real skill is not writing React code quickly. It is designing a system that stays maintainable when the product grows, the UI becomes more complex, and the platform differences start to matter.