React Native Performance i 2026: Sådan gør du dine apps lynhurtige

Alt du skal vide om React Native performance i 2026. Fra den nye arkitektur (JSI, Fabric, TurboModules) til praktiske tips om lister, rendering, state management, animationer og bundlestørrelse.

Hvorfor performance stadig betyder alt i 2026

Lad os starte med det oplagte: React Native er i 2026 nået et punkt, hvor dine apps kan føles fuldstændig native. Den nye arkitektur — Fabric, TurboModules og JSI — er nu standard i React Native 0.83 og Expo SDK 55, og det er ærligt talt en gamechanger. Men (og der er altid et men), mere kraft betyder også mere kompleksitet. Og det er præcis derfor, du læser denne guide.

Jeg har samlet alt, hvad du har brug for at vide om performanceoptimering i React Native i 2026. Fra de indre mekanismer i den nye arkitektur til helt konkrete teknikker for lister, rendering, hukommelse og bundlestørrelse. Uanset om du er i gang med din første app, eller du sidder og finjusterer en produktionsapp med millioner af brugere — her er noget for dig.

Den nye arkitektur: Fundamentet for bedre performance

JSI — JavaScript Interface

Den gamle React Native-arkitektur brugte en asynkron "bridge" til at snakke mellem JavaScript og native kode. Hver besked blev serialiseret til JSON, sendt over broen, og deserialiseret i den anden ende. Det lyder tungt, ikke? Det var det også — især ved hyppige UI-opdateringer og animationer kunne man virkelig mærke flaskehalsen.

JSI (JavaScript Interface) erstatter hele det setup med direkte, synkrone kald mellem JavaScript og native. Ingen JSON-serialisering. Bare direkte funktionskald. Resultatet? Markant lavere latens og meget mere forudsigelig performance.

// Eksempel: Med JSI kan native moduler tilgås direkte
// TurboModule-specifikation (NativeCalculator.ts)
import { TurboModuleRegistry } from 'react-native';
import type { TurboModule } from 'react-native';

export interface Spec extends TurboModule {
  multiply(a: number, b: number): number; // Synkront kald!
  asyncMultiply(a: number, b: number): Promise<number>;
}

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

Fabric — den nye renderingsmotor

Fabric er React Natives nye renderingsmotor, og den erstatter den gamle UI Manager. Kort sagt: det er en kæmpe opgradering. Her er de vigtigste fordele:

  • Synkron rendering: UI-opdateringer kan ske synkront, og det fjerner de irriterende "hop" og forsinkelser fra den gamle arkitektur
  • Concurrent rendering: Fabric understøtter React 19.2's concurrent features, så tunge renderingsoperationer kan afbrydes og genoptages uden at blokere UI'en
  • Delt ejerskab: En komponent kan nu ejes af både JavaScript- og native-tråden samtidigt — det giver langt mere flydende animationer
  • Type-sikkerhed: Fabric bruger Codegen til at generere typesikre interfaces mellem JS og native kode
// Fabric-komponent med concurrent features
import React, { useTransition, useState } from 'react';
import { View, Text, Pressable, ActivityIndicator } from 'react-native';

function HeavySearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (text: string) => {
    setQuery(text); // Opdateres med det samme (høj prioritet)
    
    startTransition(() => {
      // Tung filtrering sker i baggrunden (lav prioritet)
      const filtered = massiveDataset.filter(item =>
        item.name.toLowerCase().includes(text.toLowerCase())
      );
      setResults(filtered);
    });
  };

  return (
    <View>
      <TextInput value={query} onChangeText={handleSearch} />
      {isPending && <ActivityIndicator />}
      <FlatList data={results} renderItem={renderItem} />
    </View>
  );
}

TurboModules — intelligent modullæsning

TurboModules erstatter de gamle Native Modules, og de bringer to afgørende forbedringer med sig: lazy loading og direkte JSI-adgang.

I den gamle verden blev alle native moduler initialiseret ved app-start — uanset om de overhovedet blev brugt. Med TurboModules indlæses moduler først, når de faktisk efterspørges. Simpelt, men effektivt.

Og det gør en reel forskel. Mange udviklere har rapporteret 15-30% hurtigere opstartstider efter de migrerede til TurboModules. Det er ikke bare et tal i et benchmark — det er noget, brugerne faktisk kan mærke.

Hermes v1 — næste generation af JS-motoren

Hermes v1 er tilgængelig som opt-in i React Native 0.83 og Expo SDK 55, og forbedringerne er ganske imponerende:

  • TTI (Time to Interactive): Ca. 2,5% bedre på iOS og 7,6% på Android
  • Bundle load time: Ca. 9% bedre på iOS og 3,1% på Android
  • Renderingstid: Fra første komponent mountes til fuld rendering — ca. 7,5% bedre på iOS og 7,2% på Android
  • Bundlestørrelse: Op til 1-2 MB mindre uden kodeændringer
  • Nye sprogfunktioner: Bedre understøttelse af ES6-klasser, const/let, async/await m.m.
// Aktivér Hermes v1 i app.json (Expo SDK 55)
{
  "expo": {
    "jsEngine": "hermes",
    "experiments": {
      "hermesVersion": "v1"
    },
    "ios": {
      "jsEngine": "hermes"
    },
    "android": {
      "jsEngine": "hermes"
    }
  }
}

Bemærk: Hermes v1 kræver i Expo SDK 55 / React Native 0.83, at React Native bygges fra kildekode. Det øger native build-tiden lidt, men de runtime-fordele du får, er det absolut værd for de fleste produktionsapps.

Listeoptimering: Den store performance-udfordring

Okay, her kommer vi til det, som nok er den mest almindelige performanceudfordring i React Native-apps: lange lister. Nyhedsfeeds, kontaktlister, produktkataloger — den måde du renderer lister på, har en enorm indflydelse på brugeroplevelsen.

Så lad os dykke ned i det.

FlatList-optimering i dybden

FlatList bruger virtualisering — den renderer kun de elementer, der er synlige på skærmen, plus en buffer. Men standardindstillingerne er sjældent optimale. Her er de vigtigste props, du bør kende (og bruge):

import React, { useCallback, useMemo } from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';

interface ListItem {
  id: string;
  title: string;
  description: string;
}

const ITEM_HEIGHT = 80;

// Flyt renderItem ud af komponenten og wrap med React.memo
const ListItemComponent = React.memo(({ item }: { item: ListItem }) => (
  <View style={styles.item}>
    <Text style={styles.title}>{item.title}</Text>
    <Text style={styles.description}>{item.description}</Text>
  </View>
));

function OptimizedList({ data }: { data: ListItem[] }) {
  // Stabil renderItem-reference med useCallback
  const renderItem = useCallback(
    ({ item }: { item: ListItem }) => <ListItemComponent item={item} />,
    []
  );

  // getItemLayout eliminerer asynkrone layoutberegninger
  const getItemLayout = useCallback(
    (_: any, index: number) => ({
      length: ITEM_HEIGHT,
      offset: ITEM_HEIGHT * index,
      index,
    }),
    []
  );

  // Stabil keyExtractor
  const keyExtractor = useCallback((item: ListItem) => item.id, []);

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      // Ydeevne-props
      initialNumToRender={10}        // Antal elementer ved første rendering
      maxToRenderPerBatch={5}         // Antal elementer per batch
      windowSize={5}                  // Antal "vinduer" at holde i hukommelsen
      updateCellsBatchingPeriod={50}  // Millisekunder mellem batch-opdateringer
      removeClippedSubviews={true}    // Fjern views uden for skærmen (Android)
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: ITEM_HEIGHT,
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#eee',
  },
  title: { fontSize: 16, fontWeight: 'bold' },
  description: { fontSize: 14, color: '#666' },
});

De vigtigste props forklaret

  • getItemLayout: Har dine listeelementer ensartet højde? Så er dette den mest effektive optimering, du kan lave. Det fjerner behovet for asynkron layoutberegning og gør scrolling til specifikke positioner øjeblikkeligt
  • initialNumToRender: Bestemmer hvor mange elementer der renderes ved den første visning. Sæt det til det antal, der lige netop fylder skærmen — hverken mere eller mindre
  • maxToRenderPerBatch: Kontrollerer hvor mange elementer der renderes per batch under scrolling. Lavere værdier giver mere responsiv scrolling, men kan vise blanke områder
  • windowSize: Angiver hvor mange "sider" af elementer der holdes i hukommelsen. Værdien 5 betyder 2 sider over, den aktuelle side, og 2 sider under den synlige zone

FlashList — det hurtigere alternativ

Shopifys FlashList er ærligt talt imponerende. I stedet for at oprette og destruere views (som FlatList gør med virtualisering), genbruger FlashList eksisterende views med nyt indhold. Det er præcis samme approach som native listekomponenter bruger — UICollectionView på iOS og RecyclerView på Android.

import { FlashList } from '@shopify/flash-list';

function HighPerformanceList({ data }: { data: ListItem[] }) {
  const renderItem = useCallback(
    ({ item }: { item: ListItem }) => <ListItemComponent item={item} />,
    []
  );

  return (
    <FlashList
      data={data}
      renderItem={renderItem}
      estimatedItemSize={ITEM_HEIGHT}  // Påkrævet for FlashList
      keyExtractor={(item) => item.id}
      // FlashList har ikke brug for getItemLayout
      // View recycling håndterer performance automatisk
    />
  );
}

FlashList kræver estimatedItemSize i stedet for getItemLayout. Det er nemmere at bruge, og den håndterer automatisk elementer med variabel højde. I de fleste benchmarks er FlashList 2-5x hurtigere end FlatList for store datasæt — og den bruger markant mindre hukommelse. Det er svært at argumentere imod.

Hvornår skal du bruge hvad?

  • FlatList: Små til mellemstore lister (under 500 elementer), simpel data, eller når du helst undgår ekstra afhængigheder
  • FlashList: Store lister (500+ elementer), komplekse listeelementer, eller når scrolling-performance er kritisk
  • SectionList: Grupperede data med sektionsoverskrifter

Renderingsoptimering: Stop de unødvendige re-renders

Unødvendige re-renders er en af de mest udbredte årsager til dårlig performance i React Native. Det lyder måske banalt, men hver eneste re-render koster CPU-tid. For komplekse komponenttræer kan det hurtigt blive mærkbart — især på ældre enheder.

React.memo — memoisering af komponenter

React.memo er en higher-order component, der forhindrer re-rendering, når props ikke har ændret sig. Det er særligt nyttigt for dyre komponenttræer, som f.eks. grafer eller komplekse formularer.

// Uden memo: Re-renderes HVER gang parent opdaterer
const ExpensiveChart = ({ data, title }: ChartProps) => {
  // Tung renderingslogik her
  return <View>...</View>;
};

// Med memo: Re-renderes KUN når data eller title ændres
const ExpensiveChart = React.memo(({ data, title }: ChartProps) => {
  // Tung renderingslogik her
  return <View>...</View>;
});

// Med custom sammenligning for dyb kontrol
const ExpensiveChart = React.memo(
  ({ data, title }: ChartProps) => {
    return <View>...</View>;
  },
  (prevProps, nextProps) => {
    // Returnér true hvis props er ens (skip re-render)
    return (
      prevProps.title === nextProps.title &&
      prevProps.data.length === nextProps.data.length &&
      prevProps.data.every((item, i) => item.id === nextProps.data[i]?.id)
    );
  }
);

useMemo og useCallback — stabile referencer

Et virkelig almindeligt mønster, der forårsager unødvendige re-renders, er oprettelsen af nye objekter og funktioner ved hver rendering. Det sker oftere end man tror. useMemo og useCallback løser det ved at returnere stabile referencer.

import React, { useMemo, useCallback, useState } from 'react';

function ProductList({ products, categoryFilter }: ProductListProps) {
  const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');

  // useMemo: Undgå dyr filtrering/sortering ved hver re-render
  const filteredProducts = useMemo(() => {
    console.log('Filtrering kører'); // Kører kun ved ændring
    return products
      .filter(p => p.category === categoryFilter)
      .sort((a, b) => 
        sortOrder === 'asc' ? a.price - b.price : b.price - a.price
      );
  }, [products, categoryFilter, sortOrder]);

  // useCallback: Stabil funktionsreference til child-komponenter
  const handleProductPress = useCallback((productId: string) => {
    navigation.navigate('ProductDetail', { id: productId });
  }, [navigation]);

  // useCallback for sorteringsknap
  const toggleSort = useCallback(() => {
    setSortOrder(prev => prev === 'asc' ? 'desc' : 'asc');
  }, []);

  return (
    <View>
      <Pressable onPress={toggleSort}>
        <Text>Sortér: {sortOrder === 'asc' ? 'Stigende' : 'Faldende'}</Text>
      </Pressable>
      <FlashList
        data={filteredProducts}
        renderItem={({ item }) => (
          <ProductCard
            product={item}
            onPress={handleProductPress} // Stabil reference
          />
        )}
        estimatedItemSize={120}
      />
    </View>
  );
}

Pas på med over-memoisering

Det er fristende at pakke alt ind i useMemo og useCallback. Men hold lige — det er ikke altid en god idé.

Memoisering har sin egen omkostning. React skal gemme den forrige værdi og sammenligne dependencies ved hver render. For simple beregninger eller primitive props kan overheadet fra memoisering faktisk overstige den besparelse, den giver. Ironisk nok.

Tommelfingerregel — brug memo/useMemo/useCallback, når:

  • Beregningen er faktisk tung (filtrering, sortering, komplekse transformationer)
  • Referencen sendes som prop til en memoiseret child-komponent
  • Referencen bruges som dependency i en useEffect

Undgå dem, når:

  • Props er primitive værdier (strings, numbers, booleans)
  • Beregningen er triviel
  • Komponenten alligevel re-renderes ved enhver ændring

State management og performance

Valget af state management-strategi har direkte indflydelse på, hvor ofte dine komponenter re-renderes. I 2026 handler best practice om at adskille forskellige typer state og vælge det rigtige værktøj til hver type. Det lyder simpelt nok, men det er overraskende mange, der stadig dumper alt ned i én global store.

Opdel din state i tre kategorier

  1. Lokal UI-state: useState og useReducer — til tilstande, der kun påvirker én komponent
  2. Server-state: TanStack Query (React Query) — til data fra API'er og backend
  3. Delt klient-state: Zustand eller Jotai — til tilstande, der deles på tværs af komponenter

TanStack Query for server-state

En af de mest almindelige performance-fælder er at gemme server-data i global state (f.eks. Redux). Det fører til unødvendige re-renders, fordi hele staten opdateres, hver gang data hentes. TanStack Query løser det elegant med automatisk caching, deduplicering og baggrundsfornyelse.

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

// Hent brugerdata med automatisk caching og stale-time
function useUserProfile(userId: string) {
  return useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUserProfile(userId),
    staleTime: 5 * 60 * 1000,      // Data er frisk i 5 minutter
    gcTime: 30 * 60 * 1000,         // Hold i cache i 30 minutter
    refetchOnWindowFocus: false,     // Undgå unødvendig refetch i mobile
  });
}

// Opdatér med optimistisk UI
function useUpdateProfile() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: updateUserProfile,
    onMutate: async (newData) => {
      await queryClient.cancelQueries({ queryKey: ['user', newData.id] });
      const previousData = queryClient.getQueryData(['user', newData.id]);
      
      // Optimistisk opdatering — UI reagerer med det samme
      queryClient.setQueryData(['user', newData.id], newData);
      return { previousData };
    },
    onError: (err, newData, context) => {
      // Rul tilbage ved fejl
      queryClient.setQueryData(
        ['user', newData.id], 
        context?.previousData
      );
    },
    onSettled: (data) => {
      queryClient.invalidateQueries({ queryKey: ['user', data.id] });
    },
  });
}

Zustand for delt klient-state

Zustand er blevet det foretrukne state management-bibliotek for rigtig mange React Native-udviklere. Og det er der god grund til: det er letvægtigt (under 1 KB!), har minimal boilerplate, og — vigtigst for performance — tillader selektiv subscription.

Det betyder, at dine komponenter kun re-renderes, når den specifikke del af staten, de bruger, ændrer sig. Ikke når noget helt andet i staten opdateres.

import { create } from 'zustand';

interface AppState {
  theme: 'light' | 'dark';
  notifications: number;
  setTheme: (theme: 'light' | 'dark') => void;
  incrementNotifications: () => void;
  resetNotifications: () => void;
}

const useAppStore = create<AppState>((set) => ({
  theme: 'light',
  notifications: 0,
  setTheme: (theme) => set({ theme }),
  incrementNotifications: () => 
    set((state) => ({ notifications: state.notifications + 1 })),
  resetNotifications: () => set({ notifications: 0 }),
}));

// Komponent 1: Re-renderes KUN når theme ændres
function ThemeToggle() {
  const theme = useAppStore((state) => state.theme);
  const setTheme = useAppStore((state) => state.setTheme);
  
  return (
    <Pressable onPress={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      <Text>Nuværende tema: {theme}</Text>
    </Pressable>
  );
}

// Komponent 2: Re-renderes KUN når notifications ændres
function NotificationBadge() {
  const notifications = useAppStore((state) => state.notifications);
  
  if (notifications === 0) return null;
  
  return (
    <View style={styles.badge}>
      <Text>{notifications}</Text>
    </View>
  );
}

Læg mærke til den selektive subscription: useAppStore((state) => state.theme) sikrer, at ThemeToggle kun re-renderes, når theme ændrer sig — ikke når notifications opdateres. Sammenlignet med React Context (der re-renderer alle consumers ved enhver state-ændring) er det en kæmpe forbedring.

Billedoptimering og asset-håndtering

Billeder er ofte den største synder, når det gælder hukommelsesforbrug og langsom rendering i mobilapps. Det er nemt at overse, men et par ukomprimerede billeder kan virkelig trække performance ned.

react-native-fast-image

react-native-fast-image er stadig det foretrukne bibliotek til billedindlæsning. Under motorhjelmen bruger det SDWebImage (iOS) og Glide (Android), og det tilbyder aggressiv caching, prioritetsstyring og forudindlæsning.

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

// Preload billeder, inden de vises
FastImage.preload([
  { uri: 'https://example.com/hero.jpg', priority: FastImage.priority.high },
  { uri: 'https://example.com/thumb1.jpg', priority: FastImage.priority.normal },
  { uri: 'https://example.com/thumb2.jpg', priority: FastImage.priority.low },
]);

function ProductImage({ uri }: { uri: string }) {
  return (
    <FastImage
      source={{ uri, priority: FastImage.priority.normal }}
      style={{ width: 200, height: 200 }}
      resizeMode={FastImage.resizeMode.cover}
      // Caching-strategi
      cacheControl={FastImage.cacheControl.immutable}
    />
  );
}

Expo Image — det moderne alternativ

Bruger du Expo? Så er expo-image et rigtig godt alternativ. Det understøtter moderne billedformater, avanceret caching og pæne animerede overgange ud af boksen.

import { Image } from 'expo-image';

const blurhash = '|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WB';

function OptimizedImage({ uri }: { uri: string }) {
  return (
    <Image
      source={uri}
      placeholder={{ blurhash }}        // Viser blurhash mens billedet loader
      contentFit="cover"
      transition={200}                  // Smooth fade-in animation
      style={{ width: 300, height: 200 }}
      cachePolicy="memory-disk"         // Aggressiv caching
      recyclingKey={uri}                // Optimerer view recycling i lister
    />
  );
}

Generelle billedoptimeringer

  • Reducer billedstørrelsen: Brug billeder tilpasset den faktiske visningstørrelse. Et 3000x2000 billede til en 150x100 thumbnail er rent spild af hukommelse
  • Brug moderne formater: WebP giver 25-35% mindre filstørrelser end JPEG med sammenlignelig kvalitet
  • Implementer lazy loading: Indlæs kun billeder, der er synlige eller tæt på den synlige zone
  • Ryd op i cache: Hav en strategi for at rydde gammel billedcache, så diskforbruget ikke bare vokser og vokser

Animationer og interaktioner

Flydende animationer er afgørende for en god brugeroplevelse. Og med den nye arkitektur plus Reanimated 4 har React Native ærligt talt aldrig været bedre til animationer.

react-native-reanimated — animation på den native tråd

Den vigtigste regel for performant animation i React Native: kør animationer på den native tråd, ikke JavaScript-tråden. react-native-reanimated gør det muligt med worklets — små JavaScript-funktioner, der kompileres og kører direkte på den native UI-tråd. Det er ret elegant.

import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  withTiming,
  interpolate,
  Extrapolation,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function SwipeableCard() {
  const translateX = useSharedValue(0);
  const opacity = useSharedValue(1);

  const gesture = Gesture.Pan()
    .onUpdate((event) => {
      // Kører på den native tråd — ingen bridge-overhead!
      translateX.value = event.translationX;
      opacity.value = interpolate(
        Math.abs(event.translationX),
        [0, 200],
        [1, 0.5],
        Extrapolation.CLAMP
      );
    })
    .onEnd((event) => {
      if (Math.abs(event.translationX) > 150) {
        // Swiped langt nok — animér ud af skærmen
        translateX.value = withTiming(
          event.translationX > 0 ? 500 : -500,
          { duration: 300 }
        );
        opacity.value = withTiming(0);
      } else {
        // Snap tilbage til udgangspunkt
        translateX.value = withSpring(0);
        opacity.value = withSpring(1);
      }
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
    opacity: opacity.value,
  }));

  return (
    <GestureDetector gesture={gesture}>
      <Animated.View style={[styles.card, animatedStyle]}>
        <Text>Swipe mig!</Text>
      </Animated.View>
    </GestureDetector>
  );
}

Undgå layout thrashing

Layout thrashing sker, når du tvinger native-laget til at beregne layout gentagne gange i samme frame. Det resulterer i hakkende animationer og lav framerate. Her er et par strategier til at undgå det:

  • Brug transform i stedet for top/left: Transform-properties animeres på GPU'en og udløser ikke layout-genberegning
  • Undgå dynamisk dimensionering under animation: Beregn dimensioner på forhånd og animér kun transformationer
  • Brug useAnimatedStyle: Det sikrer, at stilopdateringer sker på den native tråd — ikke i JS

Bundlestørrelse og opstartstid

Din apps bundlestørrelse påvirker direkte downloadtid fra app stores og opstartstid. Ingen har lyst til at vente, og en stor bundle sender det forkerte signal. Her er, hvordan du holder den slank.

Analysér din bundle

# Generér bundle-rapport med react-native-bundle-visualizer
npx react-native-bundle-visualizer

# For Expo-projekter
npx expo export --dump-sourcemap
npx source-map-explorer bundle.js

Tree shaking og code splitting

Metro bundleren understøtter nu bedre tree shaking, men du kan hjælpe den på vej:

  • Importér specifikt: Brug import { map } from 'lodash-es' i stedet for import _ from 'lodash'
  • Undgå barrel exports: Filer der re-eksporterer alt fra en mappe kan forhindre tree shaking
  • Brug lazy loading af skærme: React Navigation understøtter det som standard
// Dårligt: Importerer hele lodash (>70 KB)
import _ from 'lodash';
const result = _.map(data, transform);

// Godt: Importerer kun map-funktionen (~2 KB)
import map from 'lodash/map';
const result = map(data, transform);

// Endnu bedre: Brug native JavaScript
const result = data.map(transform);

Hermes bytecode-diffing til OTA-opdateringer

En spændende ny funktion i Expo SDK 55 er Hermes bytecode-diffing. Når du bruger expo-updates eller EAS Update, kan systemet nu sende binære patches i stedet for hele bundlen. Det reducerer OTA-opdateringernes størrelse med 50-80% i mange tilfælde. Hurtigere opdateringer, lavere dataforbrug — alle vinder.

Profiling og måling af performance

Du kan ikke optimere, hvad du ikke kan måle. Det er en kliché, men den holder. Her er de vigtigste værktøjer til at finde flaskehalsene.

React DevTools Profiler

React DevTools Profiler viser dig præcist, hvilke komponenter der re-renderes, hvor lang tid hver render tager, og hvad der udløste re-renderingen. Det bør være dit første stop, når du jagter performance-problemer. Seriøst — start her.

Systrace og native profiling

For dybere analyse af native performance kan du bruge Systrace (Android) og Instruments (iOS):

# Android Systrace
npx react-native profile-hermes
adb pull /data/user/0/com.myapp/cache/sampling-profiler-trace.cpuprofile

# iOS — brug Xcode Instruments
# Product -> Profile -> Time Profiler

Custom performance-tracking

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

// Mål starttid
performance.mark('app_start');

// Mål navigation
function useTrackScreenLoad(screenName: string) {
  useEffect(() => {
    performance.mark(`${screenName}_start`);
    
    return () => {
      performance.mark(`${screenName}_end`);
      performance.measure(
        `${screenName}_load_time`,
        `${screenName}_start`,
        `${screenName}_end`
      );
    };
  }, [screenName]);
}

// Brug i en skærm
function HomeScreen() {
  useTrackScreenLoad('HomeScreen');
  
  return <View>...</View>;
}

Tjekliste: 15 performance-tips du kan bruge lige nu

Her er en hurtig opsummering af de vigtigste teknikker fra denne guide. Print den ud, sæt den på væggen — eller bare bogmærk denne side:

  1. Aktivér Hermes v1 for bedre opstartstid og runtime-performance
  2. Brug FlashList i stedet for FlatList til store lister
  3. Tilføj getItemLayout til FlatList, når elementhøjden er fast
  4. Wrap listekomponenter i React.memo for at undgå unødvendige re-renders
  5. Brug useCallback til renderItem og event handlers i lister
  6. Adskil server-state og klient-state — brug TanStack Query til API-data
  7. Brug Zustand med selektive subscriptions for minimal re-rendering
  8. Kør animationer på den native tråd med react-native-reanimated
  9. Animér med transform i stedet for layout-properties
  10. Optimer billeder: Tilpassede størrelser, moderne formater og aggressiv caching
  11. Importér specifikt i stedet for hele biblioteker
  12. Analysér din bundlestørrelse regelmæssigt med bundle visualizer
  13. Profiler din app på rigtige enheder — simulatorer giver urealistiske tal
  14. Sæt passende staleTime i TanStack Query for at reducere netværkskald
  15. Brug Hermes bytecode-diffing til mindre OTA-opdateringer

Konklusion

Performanceoptimering i React Native i 2026 handler ikke om én magisk teknik. Det handler om at forstå hele stacken — fra JavaScript-motoren til den native rendering pipeline. Med den nye arkitektur som standard er React Native hurtigere end nogensinde "out of the box", men der er stadig masser af rum til at presse endnu mere ud af platformen.

Mit råd? Start med at måle. Brug React DevTools Profiler og native profiling-værktøjer til at finde de faktiske flaskehalse. Optimér derefter målrettet — listeoptimering, renderingskontrol, smart state management, billedoptimering. Og modstå fristelsen til at over-optimere. Brug kun memoisering og andre teknikker, hvor det faktisk gør en forskel.

Med de strategier og kodeeksempler du har fået i denne guide, er du godt rustet til at bygge React Native-apps, der føles hurtige, responsive og native. For det er de i praksis.

Om Forfatteren Editorial Team

Our team of expert writers and editors.