React Native 0.86 in 2026: Edge-to-Edge Android, DevTools en Sollicitatievragen

Beheers React Native 0.86 met edge-to-edge ondersteuning voor Android 15+, DevTools verbeteringen en praktische sollicitatievragen. Complete gids met codevoorbeelden.

React Native 0.86 edge-to-edge Android ontwikkelingsworkflow diagram

React Native 0.86 brengt uitgebreide edge-to-edge ondersteuning voor Android 15+ en is daarmee de tweede opeenvolgende release zonder breaking changes. Uitgebracht in juni 2026 adresseert deze versie kritieke layout- en meet-API's die stilletjes werden beïnvloed door de verplichte edge-to-edge handhaving van Android.

Geen Breaking Changes

React Native 0.86 behoudt volledige achterwaartse compatibiliteit met 0.85. Het upgradepad vereist geen codewijzigingen voor de meeste applicaties, waardoor het een van de soepelste major versie-overgangen in de geschiedenis van React Native is.

Edge-to-Edge op Android 15 begrijpen

Edge-to-edge layouts stellen content in staat om zich uit te strekken onder systeem-UI elementen zoals de statusbalk en navigatiebalk. Android 15 dwingt dit gedrag standaard af, ongeacht de app-configuratie. React Native 0.86 zorgt ervoor dat alle meet- en layout-API's correct werken onder deze omstandigheden.

De measureInWindow functie retourneert nu accurate coördinaten wanneer de edge-to-edge modus actief is. Voorheen konden metingen worden verschoven door de hoogte van systeem-UI elementen, wat positioneringsproblemen veroorzaakte bij overlays, tooltips en zwevende actieknoppen.

SafeAreaHandler.tsxtypescript
import React, { useRef, useCallback } from 'react';
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

interface TooltipPosition {
  x: number;
  y: number;
}

export function SafeAreaHandler() {
  const buttonRef = useRef<View>(null);
  const insets = useSafeAreaInsets();

  const showTooltip = useCallback(() => {
    // measureInWindow now returns correct coordinates on Android 15+
    buttonRef.current?.measureInWindow((x, y, width, height) => {
      const position: TooltipPosition = {
        x: x + width / 2,
        // Coordinates are accurate even with edge-to-edge enabled
        y: y + height + 8,
      };
      console.log('Tooltip position:', position);
    });
  }, []);

  return (
    <View style={[styles.container, { paddingTop: insets.top }]}>
      <View ref={buttonRef} collapsable={false}>
        <TouchableOpacity onPress={showTooltip} style={styles.button}>
          <Text style={styles.buttonText}>Show Tooltip</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
  button: { backgroundColor: '#007AFF', padding: 16, borderRadius: 8 },
  buttonText: { color: '#FFFFFF', fontWeight: '600' },
});

De eigenschap collapsable={false} zorgt ervoor dat de View een native referentie behoudt voor metingen. Zonder deze instelling kan React Native de native view wegoptimaliseren, waardoor measureInWindow faalt.

KeyboardAvoidingView Fixes voor Android 15

De KeyboardAvoidingView component berekent de beschikbare ruimte incorrect wanneer de edge-to-edge modus actief is. Versie 0.86 lost dit op door systeem-UI insets mee te nemen in de berekening van de beschikbare hoogte.

ChatInput.tsxtypescript
import React, { useState } from 'react';
import {
  KeyboardAvoidingView,
  TextInput,
  Platform,
  StyleSheet,
  View,
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export function ChatInput() {
  const [message, setMessage] = useState('');
  const insets = useSafeAreaInsets();

  return (
    <KeyboardAvoidingView
      // behavior="padding" works correctly on Android 15+ edge-to-edge
      behavior={Platform.OS === 'ios' ? 'padding' : 'padding'}
      style={styles.container}
      // keyboardVerticalOffset accounts for headers and safe areas
      keyboardVerticalOffset={Platform.select({ ios: 88, android: 0 })}
    >
      <View style={styles.content}>
        {/* Chat messages would render here */}
      </View>
      <View style={[styles.inputContainer, { paddingBottom: insets.bottom }]}>
        <TextInput
          value={message}
          onChangeText={setMessage}
          placeholder="Type a message..."
          style={styles.input}
          multiline
        />
      </View>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  content: { flex: 1 },
  inputContainer: { borderTopWidth: 1, borderTopColor: '#E5E5E5', padding: 8 },
  input: { minHeight: 40, padding: 12, backgroundColor: '#F5F5F5', borderRadius: 20 },
});

Op Android 15 veroorzaakt het gebruik van behavior="height" vaak layout-sprongen. Het padding gedrag biedt vloeiendere animaties en voorspelbaardere positionering met edge-to-edge ingeschakeld.

StatusBar Updates tijdens Modal Weergave

Een hardnekkige bug verhinderde StatusBar stijl- en zichtbaarheidswijzigingen terwijl een Modal geopend was. React Native 0.86 lost dit op en maakt dynamische statusbalk-theming mogelijk in modale flows.

ThemedModal.tsxtypescript
import React, { useState, useEffect } from 'react';
import { Modal, View, StatusBar, Text, Pressable, StyleSheet } from 'react-native';

interface ThemedModalProps {
  visible: boolean;
  onClose: () => void;
  darkMode?: boolean;
}

export function ThemedModal({ visible, onClose, darkMode = false }: ThemedModalProps) {
  // StatusBar changes now apply correctly while modal is visible
  useEffect(() => {
    if (visible) {
      StatusBar.setBarStyle(darkMode ? 'light-content' : 'dark-content', true);
      StatusBar.setBackgroundColor(darkMode ? '#1A1A1A' : '#FFFFFF', true);
    }
    return () => {
      // Restore original status bar when modal closes
      StatusBar.setBarStyle('dark-content', true);
      StatusBar.setBackgroundColor('#FFFFFF', true);
    };
  }, [visible, darkMode]);

  return (
    <Modal visible={visible} animationType="slide" onRequestClose={onClose}>
      <View style={[styles.modalContent, darkMode && styles.darkBackground]}>
        <StatusBar
          barStyle={darkMode ? 'light-content' : 'dark-content'}
          backgroundColor={darkMode ? '#1A1A1A' : '#FFFFFF'}
        />
        <Text style={[styles.title, darkMode && styles.lightText]}>
          Modal Content
        </Text>
        <Pressable onPress={onClose} style={styles.closeButton}>
          <Text style={styles.closeButtonText}>Close</Text>
        </Pressable>
      </View>
    </Modal>
  );
}

const styles = StyleSheet.create({
  modalContent: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#FFFFFF' },
  darkBackground: { backgroundColor: '#1A1A1A' },
  title: { fontSize: 24, fontWeight: 'bold', color: '#000000' },
  lightText: { color: '#FFFFFF' },
  closeButton: { marginTop: 20, padding: 12, backgroundColor: '#007AFF', borderRadius: 8 },
  closeButtonText: { color: '#FFFFFF', fontWeight: '600' },
});

Deze fix is bijzonder belangrijk voor apps die dark mode toggles implementeren binnen modale flows, zoals instellingenschermen of afbeeldingsviewers.

Klaar om je React Native gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

DevTools Lichte en Donkere Modus Emulatie

React Native DevTools introduceert Emulation.setEmulatedMedia ondersteuning, wat directe thema-wisseling mogelijk maakt zonder wijzigingen aan apparaat- of emulatorconfiguraties. Deze functie is toegankelijk via het Command Palette met Cmd+Shift+P (macOS) of Ctrl+Shift+P (Windows/Linux).

ThemeProvider.tsxtypescript
import React, { createContext, useContext, useState, useEffect } from 'react';
import { useColorScheme, Appearance } from 'react-native';

type Theme = 'light' | 'dark';

interface ThemeContextValue {
  theme: Theme;
  toggleTheme: () => void;
  colors: typeof lightColors;
}

const lightColors = {
  background: '#FFFFFF',
  surface: '#F5F5F5',
  text: '#000000',
  textSecondary: '#666666',
  primary: '#007AFF',
  border: '#E5E5E5',
};

const darkColors = {
  background: '#1A1A1A',
  surface: '#2D2D2D',
  text: '#FFFFFF',
  textSecondary: '#A0A0A0',
  primary: '#0A84FF',
  border: '#3D3D3D',
};

const ThemeContext = createContext<ThemeContextValue | null>(null);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  // DevTools emulation triggers colorScheme changes via setEmulatedMedia
  const systemColorScheme = useColorScheme();
  const [theme, setTheme] = useState<Theme>(systemColorScheme ?? 'light');

  useEffect(() => {
    // Listen for DevTools theme emulation changes
    const subscription = Appearance.addChangeListener(({ colorScheme }) => {
      if (colorScheme) {
        setTheme(colorScheme);
      }
    });
    return () => subscription?.remove();
  }, []);

  const toggleTheme = () => setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
  const colors = theme === 'dark' ? darkColors : lightColors;

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme, colors }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme(): ThemeContextValue {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

De geëmuleerde media-status wordt gereset wanneer DevTools de verbinding verbreekt, waardoor productie-builds onbeïnvloed blijven door thema-tests tijdens ontwikkeling.

Sollicitatievragen: React Native 0.86 en Edge-to-Edge

Technische sollicitatiegesprekken in 2026 richten zich steeds meer op Android 15 compatibiliteit en edge-to-edge implementatie. Het beheersen van deze concepten toont begrip van moderne mobiele ontwikkelingspraktijken. Voor uitgebreide sollicitatievoorbereiding kan de module React Native debugging sollicitatievragen worden geraadpleegd.

Wat is edge-to-edge modus en waarom dwingt Android 15 deze af?

De edge-to-edge modus breidt app-content uit onder systeem-UI elementen (statusbalk, navigatiebalk, gesture-indicatoren). Android 15 dwingt dit gedrag standaard af om meeslepende ervaringen en consistente UI over het hele platform te bieden. Apps moeten safe area insets afhandelen om te voorkomen dat content wordt verborgen door de systeem-UI.

Hoe verandert het gedrag van measureInWindow met edge-to-edge ingeschakeld?

Vóór React Native 0.86 retourneerde measureInWindow coördinaten relatief aan het zichtbare venster, dat systeem-UI gebieden uitsloot. Met edge-to-edge strekt het venster zich uit tot de schermranden, maar metingen waren foutief verschoven. Versie 0.86 zorgt ervoor dat coördinaten nauwkeurig zijn ongeacht de edge-to-edge status.

Wat is het aanbevolen KeyboardAvoidingView gedrag op Android 15?

Op Android 15 met edge-to-edge ingeschakeld wordt het gebruik van behavior="padding" aanbevolen. Het height gedrag kan layout-sprongen veroorzaken omdat de berekening van de beschikbare hoogte verandert wanneer het toetsenbord verschijnt. Het padding gedrag biedt vloeiendere overgangen en voorspelbaardere positionering.

Hoe verschillen safe area insets tussen iOS en Android edge-to-edge?

Op iOS bestaan safe area insets sinds de iPhone X voor de notch en home-indicator. Op Android edge-to-edge omvatten insets de hoogte van de statusbalk, navigatiebalk en gesture-indicator gebieden. De react-native-safe-area-context bibliotheek biedt cross-platform inset waarden via useSafeAreaInsets().

Pressable android_ripple met PlatformColor

React Native 0.86 voegt PlatformColor ondersteuning toe aan de android_ripple eigenschap, waardoor dynamische ripple-kleuren mogelijk zijn die de systeemthema-instellingen respecteren.

ThemedButton.tsxtypescript
import React from 'react';
import { Pressable, Text, PlatformColor, Platform, StyleSheet } from 'react-native';

interface ThemedButtonProps {
  title: string;
  onPress: () => void;
}

export function ThemedButton({ title, onPress }: ThemedButtonProps) {
  return (
    <Pressable
      onPress={onPress}
      style={({ pressed }) => [
        styles.button,
        pressed && styles.pressed,
      ]}
      android_ripple={{
        // PlatformColor adapts to system theme automatically
        color: Platform.OS === 'android'
          ? PlatformColor('?attr/colorControlHighlight')
          : undefined,
        borderless: false,
        foreground: true,
      }}
    >
      <Text style={styles.text}>{title}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: {
    padding: 16,
    backgroundColor: Platform.select({
      android: PlatformColor('?attr/colorPrimary'),
      default: '#007AFF',
    }),
    borderRadius: 8,
    alignItems: 'center',
  },
  pressed: { opacity: 0.8 },
  text: { color: '#FFFFFF', fontWeight: '600', fontSize: 16 },
});

Het gebruik van ?attr/colorControlHighlight zorgt ervoor dat de ripple-kleur overeenkomt met Material Design richtlijnen en zich aanpast aan lichte/donkere thema's die op systeemniveau zijn geconfigureerd.

Image.getSize Retourneert Accurate Dimensies

De methoden Image.getSize en Image.getSizeWithHeaders retourneren nu originele afbeeldingsdimensies in plaats van gedownsamplede waarden. Deze fix is essentieel voor het implementeren van correcte aspect ratio berekeningen en responsieve afbeeldingslayouts.

ResponsiveImage.tsxtypescript
import React, { useState, useEffect } from 'react';
import { Image, View, useWindowDimensions, StyleSheet } from 'react-native';

interface ResponsiveImageProps {
  uri: string;
  maxHeight?: number;
}

export function ResponsiveImage({ uri, maxHeight = 400 }: ResponsiveImageProps) {
  const { width: screenWidth } = useWindowDimensions();
  const [dimensions, setDimensions] = useState({ width: screenWidth, height: 200 });

  useEffect(() => {
    // getSize now returns true source dimensions, not downsampled values
    Image.getSize(
      uri,
      (width, height) => {
        const aspectRatio = width / height;
        let calculatedHeight = screenWidth / aspectRatio;
        
        // Constrain to maxHeight while maintaining aspect ratio
        if (calculatedHeight > maxHeight) {
          calculatedHeight = maxHeight;
        }
        
        setDimensions({
          width: screenWidth,
          height: calculatedHeight,
        });
      },
      (error) => {
        console.error('Failed to get image size:', error);
      }
    );
  }, [uri, screenWidth, maxHeight]);

  return (
    <View style={styles.container}>
      <Image
        source={{ uri }}
        style={{ width: dimensions.width, height: dimensions.height }}
        resizeMode="cover"
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { width: '100%' },
});

Deze fix elimineert de noodzaak voor workarounds die afbeeldingsdimensies ophaalden via native modules of server-side beeldverwerking.

Verwerking van Grote HTTP Responses Zonder OutOfMemoryError

De NetworkingModule gooide voorheen een OutOfMemoryError bij het verwerken van grote HTTP responses. Versie 0.86 implementeert chunked verwerking voor responses die geheugendrempels overschrijden.

LargeFileDownload.tsxtypescript
import { useState, useCallback } from 'react';

interface DownloadProgress {
  loaded: number;
  total: number;
  percentage: number;
}

export function useLargeFileDownload() {
  const [progress, setProgress] = useState<DownloadProgress | null>(null);
  const [error, setError] = useState<string | null>(null);

  const downloadFile = useCallback(async (url: string): Promise<Blob | null> => {
    try {
      setError(null);
      setProgress({ loaded: 0, total: 0, percentage: 0 });

      const response = await fetch(url);
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const contentLength = response.headers.get('Content-Length');
      const total = contentLength ? parseInt(contentLength, 10) : 0;

      // NetworkingModule now handles large responses without OutOfMemoryError
      const reader = response.body?.getReader();
      if (!reader) {
        throw new Error('Response body is not readable');
      }

      const chunks: Uint8Array[] = [];
      let loaded = 0;

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        
        chunks.push(value);
        loaded += value.length;
        
        setProgress({
          loaded,
          total,
          percentage: total > 0 ? Math.round((loaded / total) * 100) : 0,
        });
      }

      const blob = new Blob(chunks);
      setProgress({ loaded, total, percentage: 100 });
      return blob;
    } catch (err) {
      const message = err instanceof Error ? err.message : 'Download failed';
      setError(message);
      return null;
    }
  }, []);

  return { downloadFile, progress, error };
}

Voor bestandsdownloads groter dan 50MB wordt het gebruik van react-native-blob-util of vergelijkbare native bestandsbeheer-bibliotheken aanbevolen voor beter geheugenbeheer.

De Cookie header die via de WebSocket constructor werd doorgegeven, werd verwijderd voordat deze de server bereikte. Dit verhinderde sessie-gebaseerde authenticatie voor WebSocket verbindingen.

AuthenticatedWebSocket.tstypescript
type MessageHandler = (data: string) => void;
type ErrorHandler = (error: Event) => void;

interface WebSocketOptions {
  url: string;
  sessionCookie: string;
  onMessage: MessageHandler;
  onError?: ErrorHandler;
}

export function createAuthenticatedWebSocket({
  url,
  sessionCookie,
  onMessage,
  onError,
}: WebSocketOptions): WebSocket {
  // Cookie header now reaches the server correctly in 0.86
  const ws = new WebSocket(url, undefined, {
    headers: {
      Cookie: sessionCookie,
      // Additional headers as needed
      'X-Client-Version': '1.0.0',
    },
  });

  ws.onopen = () => {
    console.log('WebSocket connected with session cookie');
  };

  ws.onmessage = (event) => {
    if (typeof event.data === 'string') {
      onMessage(event.data);
    }
  };

  ws.onerror = (error) => {
    console.error('WebSocket error:', error);
    onError?.(error);
  };

  ws.onclose = (event) => {
    console.log(`WebSocket closed: ${event.code} ${event.reason}`);
  };

  return ws;
}

Deze fix is cruciaal voor applicaties die cookie-gebaseerd sessiebeheer gebruiken in combinatie met real-time functionaliteiten. De module React Native networking sollicitatievragen behandelt WebSocket implementatiepatronen in detail.

Conclusie

  • React Native 0.86 levert verplichte edge-to-edge fixes voor Android 15 zonder breaking changes
  • measureInWindow, KeyboardAvoidingView en Dimensions werken correct met edge-to-edge ingeschakeld
  • StatusBar updates worden nu toegepast terwijl Modal componenten zichtbaar zijn
  • DevTools thema-emulatie versnelt dark mode ontwikkeling en testen
  • PlatformColor ondersteuning in android_ripple maakt thema-bewuste touch feedback mogelijk
  • Image.getSize retourneert accurate originele dimensies voor responsieve layouts
  • Grote HTTP responses veroorzaken geen OutOfMemoryError meer
  • WebSocket Cookie headers bereiken de server zoals verwacht

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Tags

#react-native
#android
#mobile-development
#edge-to-edge
#devtools

Delen

Gerelateerde artikelen