# React Native 0.86 Năm 2026: Edge-to-Edge Android, DevTools và Câu Hỏi Phỏng Vấn > Làm chủ React Native 0.86 với hỗ trợ edge-to-edge Android 15, cải tiến DevTools và các câu hỏi phỏng vấn thực tế. Hướng dẫn đầy đủ với ví dụ code. - Published: 2026-07-18 - Updated: 2026-07-18 - Author: SharpSkill - Tags: react-native, android, mobile-development, edge-to-edge, devtools - Reading time: 12 min --- React Native 0.86 mang đến hỗ trợ edge-to-edge toàn diện cho Android 15+, đánh dấu phiên bản thứ hai liên tiếp không có breaking changes. Được phát hành vào tháng 6 năm 2026, phiên bản này giải quyết các vấn đề API layout và measurement đã bị ảnh hưởng âm thầm bởi chính sách edge-to-edge bắt buộc của Android. > **Không Có Breaking Changes** > > React Native 0.86 duy trì khả năng tương thích hoàn toàn với phiên bản 0.85. Quá trình nâng cấp không yêu cầu sửa đổi code cho hầu hết các ứng dụng, khiến đây trở thành một trong những lần chuyển đổi phiên bản major mượt mà nhất trong lịch sử React Native. ## Hiểu Về Edge-to-Edge Trên Android 15 Layout edge-to-edge cho phép nội dung mở rộng xuống dưới các thành phần UI hệ thống như thanh trạng thái và thanh điều hướng. Android 15 áp dụng hành vi này theo mặc định, bất kể cấu hình ứng dụng. React Native 0.86 đảm bảo tất cả các API measurement và layout hoạt động chính xác trong điều kiện này. Hàm `measureInWindow` hiện trả về tọa độ chính xác khi chế độ edge-to-edge được kích hoạt. Trước đây, các phép đo có thể bị lệch bằng chiều cao của các thành phần UI hệ thống, gây ra lỗi định vị trên overlay, tooltip và floating action button. ```typescript // SafeAreaHandler.tsx 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(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 ( Show Tooltip ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, button: { backgroundColor: '#007AFF', padding: 16, borderRadius: 8 }, buttonText: { color: '#FFFFFF', fontWeight: '600' }, }); ``` Prop `collapsable={false}` đảm bảo View duy trì tham chiếu native để đo lường. Nếu không có điều này, React Native có thể tối ưu hóa View native đó, khiến `measureInWindow` thất bại. ## Sửa Lỗi KeyboardAvoidingView Cho Android 15 Component [KeyboardAvoidingView](https://reactnative.dev/docs/keyboardavoidingview) tính toán không gian khả dụng không chính xác khi chế độ edge-to-edge được kích hoạt. Phiên bản 0.86 sửa lỗi này bằng cách tính toán các insets UI hệ thống trong phép tính chiều cao khả dụng. ```typescript // ChatInput.tsx 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 ( {/* Chat messages would render here */} ); } 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 }, }); ``` Trên Android 15, sử dụng `behavior="height"` thường gây ra hiện tượng nhảy layout. Behavior `padding` cung cấp animation mượt mà hơn và định vị dễ dự đoán hơn khi edge-to-edge được kích hoạt. ## Cập Nhật StatusBar Trong Khi Hiển Thị Modal Một bug tồn tại lâu đã ngăn cản việc thay đổi style và visibility của StatusBar khi Modal đang mở. React Native 0.86 giải quyết vấn đề này, cho phép tùy chỉnh status bar động trong các luồng modal. ```typescript // ThemedModal.tsx 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 Content Close ); } 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' }, }); ``` Bản sửa lỗi này đặc biệt quan trọng cho các ứng dụng triển khai toggle dark mode trong luồng modal, chẳng hạn như màn hình cài đặt hoặc trình xem hình ảnh. ## Mô Phỏng Light và Dark Mode Trong DevTools React Native DevTools giới thiệu hỗ trợ [Emulation.setEmulatedMedia](https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setEmulatedMedia), cho phép chuyển đổi theme ngay lập tức mà không cần thay đổi cấu hình thiết bị hoặc emulator. Truy cập tính năng này thông qua Command Palette bằng `Cmd+Shift+P` (macOS) hoặc `Ctrl+Shift+P` (Windows/Linux). ```typescript // ThemeProvider.tsx 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(null); export function ThemeProvider({ children }: { children: React.ReactNode }) { // DevTools emulation triggers colorScheme changes via setEmulatedMedia const systemColorScheme = useColorScheme(); const [theme, setTheme] = useState(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 ( {children} ); } export function useTheme(): ThemeContextValue { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within ThemeProvider'); } return context; } ``` Trạng thái media được mô phỏng sẽ được reset khi DevTools ngắt kết nối, đảm bảo các bản build production không bị ảnh hưởng bởi việc test theme trong quá trình development. ## Câu Hỏi Phỏng Vấn: React Native 0.86 và Edge-to-Edge Các cuộc phỏng vấn kỹ thuật năm 2026 ngày càng tập trung vào khả năng tương thích Android 15 và triển khai edge-to-edge. Nắm vững các khái niệm này thể hiện sự hiểu biết về các thực hành phát triển mobile hiện đại. Để chuẩn bị phỏng vấn toàn diện, hãy khám phá module [câu hỏi phỏng vấn debugging React Native](/technologies/react-native/interview-questions/rn-debugging). ### Chế độ edge-to-edge là gì và tại sao Android 15 áp dụng nó? Chế độ edge-to-edge mở rộng nội dung ứng dụng xuống dưới các thành phần UI hệ thống (thanh trạng thái, thanh điều hướng, chỉ báo gesture). Android 15 áp dụng hành vi này theo mặc định để cung cấp trải nghiệm nhập vai và UI nhất quán trên toàn nền tảng. Các ứng dụng phải xử lý safe area insets để ngăn nội dung bị che khuất bởi UI hệ thống. ### Hành vi measureInWindow thay đổi như thế nào khi edge-to-edge được kích hoạt? Trước React Native 0.86, `measureInWindow` trả về tọa độ tương đối so với cửa sổ hiển thị, không bao gồm các khu vực UI hệ thống. Với edge-to-edge, cửa sổ mở rộng đến các cạnh màn hình, nhưng các phép đo bị sai do offset. Phiên bản 0.86 đảm bảo tọa độ chính xác bất kể trạng thái edge-to-edge. ### Behavior KeyboardAvoidingView được khuyến nghị trên Android 15 là gì? Sử dụng `behavior="padding"` trên Android 15 với edge-to-edge được kích hoạt. Behavior `height` có thể gây ra hiện tượng nhảy layout vì phép tính chiều cao khả dụng thay đổi khi bàn phím xuất hiện. Behavior `padding` cung cấp chuyển đổi mượt mà hơn và định vị dễ dự đoán hơn. ### Safe area insets khác nhau như thế nào giữa iOS và Android edge-to-edge? Trên iOS, safe area insets đã tồn tại từ iPhone X cho notch và home indicator. Trên Android edge-to-edge, insets bao gồm chiều cao thanh trạng thái, chiều cao thanh điều hướng và các khu vực chỉ báo gesture. Thư viện `react-native-safe-area-context` cung cấp giá trị insets đa nền tảng thông qua `useSafeAreaInsets()`. ## Pressable android_ripple Với PlatformColor React Native 0.86 thêm hỗ trợ [PlatformColor](https://reactnative.dev/docs/platformcolor) cho prop `android_ripple`, cho phép màu ripple động tự động theo cài đặt theme hệ thống. ```typescript // ThemedButton.tsx 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 ( [ 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, }} > {title} ); } 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 }, }); ``` Sử dụng `?attr/colorControlHighlight` đảm bảo màu ripple tuân theo nguyên tắc Material Design và thích ứng với theme sáng/tối được cấu hình ở cấp hệ thống. ## Image.getSize Trả Về Kích Thước Chính Xác Các phương thức `Image.getSize` và `Image.getSizeWithHeaders` hiện trả về kích thước hình ảnh gốc thay vì giá trị đã được downsample. Bản sửa lỗi này rất quan trọng để triển khai tính toán aspect ratio chính xác và layout hình ảnh responsive. ```typescript // ResponsiveImage.tsx 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 ( ); } const styles = StyleSheet.create({ container: { width: '100%' }, }); ``` Bản sửa lỗi này loại bỏ nhu cầu về các workaround lấy kích thước hình ảnh thông qua module native hoặc xử lý hình ảnh phía server. ## Xử Lý Response HTTP Lớn Không Gây OutOfMemoryError `NetworkingModule` trước đây ném `OutOfMemoryError` khi xử lý các response HTTP lớn. Phiên bản 0.86 triển khai xử lý theo chunk cho các response vượt quá ngưỡng bộ nhớ. ```typescript // LargeFileDownload.tsx import { useState, useCallback } from 'react'; interface DownloadProgress { loaded: number; total: number; percentage: number; } export function useLargeFileDownload() { const [progress, setProgress] = useState(null); const [error, setError] = useState(null); const downloadFile = useCallback(async (url: string): Promise => { 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 }; } ``` Đối với việc tải file vượt quá 50MB, hãy cân nhắc sử dụng [react-native-blob-util](https://github.com/RonRadtke/react-native-blob-util) hoặc các thư viện xử lý file native tương tự để quản lý bộ nhớ tốt hơn. ## Sửa Lỗi Header Cookie WebSocket Header Cookie được truyền qua constructor WebSocket trước đây bị loại bỏ trước khi đến server. Điều này ngăn cản xác thực dựa trên session cho các kết nối WebSocket. ```typescript // AuthenticatedWebSocket.ts 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; } ``` Bản sửa lỗi này rất quan trọng cho các ứng dụng sử dụng quản lý session dựa trên cookie cùng với các tính năng real-time. Module [câu hỏi phỏng vấn networking React Native](/technologies/react-native/interview-questions/rn-networking-api) đề cập sâu về các pattern triển khai WebSocket. ## Kết Luận - React Native 0.86 cung cấp các bản sửa lỗi edge-to-edge bắt buộc cho Android 15 mà không có breaking changes - `measureInWindow`, `KeyboardAvoidingView` và `Dimensions` hoạt động chính xác với edge-to-edge được kích hoạt - Cập nhật StatusBar hiện áp dụng khi component Modal đang hiển thị - Mô phỏng theme DevTools tăng tốc phát triển và kiểm thử dark mode - Hỗ trợ `PlatformColor` trong `android_ripple` cho phép phản hồi chạm theo theme - `Image.getSize` trả về kích thước gốc chính xác cho layout responsive - Response HTTP lớn không còn gây ra `OutOfMemoryError` - Header Cookie WebSocket đến server như mong đợi --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/vi/blog/react-native/react-native-086-edge-to-edge-android-devtools-interview-questions