正在加载,请稍候…

React Native Performance Optimization: Hermes, New Architecture, and Beyond

A comprehensive guide to optimizing React Native apps with Hermes engine, New Architecture migration, FlatList tuning, and native module best practices.

React Native Performance Optimization: Hermes, New Architecture, and Beyond

React Native has evolved dramatically. With the Hermes JavaScript engine now the default and the New Architecture (Fabric + JSI) rolling out across major apps, developers have powerful new tools to build truly performant mobile experiences.

Understanding the React Native Threading Model

React Native runs on three threads:

  • JS Thread: Executes your JavaScript code
  • Main/UI Thread: Handles native UI rendering
  • Shadow Thread: Calculates layouts using Yoga

Traditional React Native bridged communication between JS and Native asynchronously, causing frame drops and jank. The New Architecture replaces this bridge with JSI (JavaScript Interface), enabling synchronous native calls.

Enabling and Optimizing Hermes

Hermes is a JavaScript engine optimized specifically for React Native. It precompiles JavaScript to bytecode at build time, reducing startup time and memory usage.

Enabling Hermes

In android/app/build.gradle:

project.ext.react = [
  enableHermes: true
]

In ios/Podfile:

use_react_native!(
  :hermes_enabled => true
)

Hermes Performance Characteristics

Hermes excels at startup time, memory efficiency, and Time to Interactive (TTI). Benchmark data from production apps shows 40-60% improvement in TTI with Hermes vs V8.

Profiling with Hermes

Use the Hermes profiler via Flipper or the standalone profiler:

npx react-native start --experimental-debugger

Migrating to New Architecture

The New Architecture consists of:

  • Fabric: New renderer for synchronous UI operations
  • JSI: Direct JS-to-native bindings without the bridge
  • TurboModules: Lazy-loaded native modules via JSI
  • Codegen: Type-safe native module interfaces

Step-by-Step Migration

Enable New Architecture in Android:

// android/gradle.properties
newArchEnabled=true

Enable New Architecture in iOS:

cd ios && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install

Create a TurboModule spec file NativeMyModule.ts:

import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  multiply(a: number, b: number): Promise<number>;
  getDeviceInfo(): Promise<{ model: string; os: string }>;
}

export default TurboModuleRegistry.getEnforcing<Spec>('MyModule');

Optimizing FlatList and VirtualizedList

FlatList is one of the most commonly misused components. Use getItemLayout when all items have fixed height:

const ITEM_HEIGHT = 80;

<FlatList
  data={items}
  getItemLayout={(data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  })}
  renderItem={({ item }) => <ItemRow item={item} />}
/>

Memoize renderItem

const renderItem = useCallback(({ item }) => (
  <MemoizedItemRow item={item} />
), []);

const MemoizedItemRow = React.memo(({ item }) => {
  return (
    <View style={styles.row}>
      <Text>{item.title}</Text>
      <Text>{item.subtitle}</Text>
    </View>
  );
}, (prevProps, nextProps) => prevProps.item.id === nextProps.item.id);

Key windowSize and maxToRenderPerBatch

<FlatList
  windowSize={5}
  maxToRenderPerBatch={10}
  initialNumToRender={8}
  updateCellsBatchingPeriod={50}
  removeClippedSubviews={true}
/>

Image Optimization

Use react-native-fast-image for better caching:

import FastImage from 'react-native-fast-image';

<FastImage
  style={styles.image}
  source={{
    uri: 'https://example.com/image.jpg',
    priority: FastImage.priority.normal,
    cache: FastImage.cacheControl.immutable,
  }}
  resizeMode={FastImage.resizeMode.cover}
/>

Native Module Best Practices with JSI

With New Architecture, write JSI modules for performance-critical operations:

// ios/MyJSIModule.cpp
void MyJSIModule::install(jsi::Runtime& runtime) {
  auto multiply = jsi::Function::createFromHostFunction(
    runtime,
    jsi::PropNameID::forAscii(runtime, "multiply"),
    2,
    [](jsi::Runtime& runtime, const jsi::Value& thisValue,
       const jsi::Value* args, size_t count) -> jsi::Value {
      double a = args[0].asNumber();
      double b = args[1].asNumber();
      return jsi::Value(a * b);
    }
  );
  runtime.global().setProperty(runtime, "multiply", std::move(multiply));
}

Avoiding Common Performance Pitfalls

Avoid anonymous functions in render:

// Bad - creates new function each render
<TouchableOpacity onPress={() => handlePress(item.id)}>

// Good - stable reference
const handleItemPress = useCallback(() => handlePress(item.id), [item.id]);
<TouchableOpacity onPress={handleItemPress}>

Use InteractionManager for expensive operations:

import { InteractionManager } from 'react-native';

useEffect(() => {
  const task = InteractionManager.runAfterInteractions(() => {
    processLargeDataset(data);
  });
  return () => task.cancel();
}, [data]);

Measuring Performance

Use custom performance marks:

import { PerformanceObserver, performance } from 'react-native';

performance.mark('render-start');
// render code
performance.mark('render-end');
performance.measure('render-duration', 'render-start', 'render-end');

const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log(`${entry.name}: ${entry.duration}ms`);
  });
});
observer.observe({ entryTypes: ['measure'] });

Conclusion

React Native performance optimization in 2026 is a multi-layered discipline. Start with Hermes and New Architecture adoption for foundational gains. Optimize your lists with proper FlatList configuration. Minimize your bundle with tree shaking and lazy loading. Profile early and often with Flipper. The combination of these techniques can bring your React Native app within striking distance of native performance.