# React Native 0.86 ในปี 2026: Edge-to-Edge Android, DevTools และคำถามสัมภาษณ์ > เชี่ยวชาญ React Native 0.86 พร้อมการรองรับ edge-to-edge Android 15, การปรับปรุง DevTools และคำถามสัมภาษณ์เชิงปฏิบัติ คู่มือฉบับสมบูรณ์พร้อมตัวอย่างโค้ด - 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 นำเสนอการรองรับ edge-to-edge อย่างครอบคลุมสำหรับ Android 15+ ทำให้เป็นรุ่นที่สองติดต่อกันที่ไม่มี breaking changes เปิดตัวในเดือนมิถุนายน 2026 เวอร์ชันนี้แก้ไขปัญหา API ของ layout และ measurement ที่ถูกกระทบอย่างเงียบ ๆ จากนโยบาย edge-to-edge บังคับของ Android > **ไม่มี Breaking Changes** > > React Native 0.86 ยังคงความเข้ากันได้อย่างสมบูรณ์กับเวอร์ชัน 0.85 กระบวนการอัปเกรดไม่ต้องการการแก้ไขโค้ดสำหรับแอปพลิเคชันส่วนใหญ่ ทำให้เป็นหนึ่งในการเปลี่ยนผ่านเวอร์ชัน major ที่ราบรื่นที่สุดในประวัติศาสตร์ React Native ## ทำความเข้าใจ Edge-to-Edge บน Android 15 Layout แบบ edge-to-edge อนุญาตให้เนื้อหาขยายไปใต้องค์ประกอบ UI ของระบบ เช่น status bar และ navigation bar Android 15 บังคับใช้พฤติกรรมนี้โดยค่าเริ่มต้น โดยไม่คำนึงถึงการตั้งค่าแอปพลิเคชัน React Native 0.86 รับประกันว่า API ทั้งหมดของ measurement และ layout ทำงานได้อย่างถูกต้องภายใต้เงื่อนไขเหล่านี้ ฟังก์ชัน `measureInWindow` ตอนนี้ส่งคืนพิกัดที่ถูกต้องเมื่อโหมด edge-to-edge ถูกเปิดใช้งาน ก่อนหน้านี้ การวัดอาจถูกเลื่อนโดยความสูงขององค์ประกอบ UI ของระบบ ทำให้เกิดบั๊กในการวางตำแหน่งบน overlay, tooltip และ 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}` รับประกันว่า View จะรักษา reference ของ native สำหรับการวัด หากไม่มีสิ่งนี้ React Native อาจทำการ optimize View native นั้นออกไป ทำให้ `measureInWindow` ล้มเหลว ## การแก้ไข KeyboardAvoidingView สำหรับ Android 15 Component [KeyboardAvoidingView](https://reactnative.dev/docs/keyboardavoidingview) คำนวณพื้นที่ว่างไม่ถูกต้องเมื่อโหมด edge-to-edge ถูกเปิดใช้งาน เวอร์ชัน 0.86 แก้ไขปัญหานี้โดยการนำ insets ของ UI ระบบมาคำนวณในความสูงที่ใช้งานได้ ```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 }, }); ``` บน Android 15 การใช้ `behavior="height"` มักทำให้เกิดการกระโดดของ layout Behavior `padding` ให้ animation ที่นุ่มนวลกว่าและการวางตำแหน่งที่คาดเดาได้มากขึ้นเมื่อ edge-to-edge ถูกเปิดใช้งาน ## การอัปเดต StatusBar ระหว่างการแสดง Modal บั๊กที่คงอยู่นานป้องกันการเปลี่ยนแปลง style และ visibility ของ StatusBar ขณะที่ Modal เปิดอยู่ React Native 0.86 แก้ไขปัญหานี้ ทำให้สามารถปรับแต่ง status bar แบบไดนามิกในขั้นตอน 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' }, }); ``` การแก้ไขนี้มีความสำคัญเป็นพิเศษสำหรับแอปพลิเคชันที่ใช้งานการสลับ dark mode ในขั้นตอน modal เช่น หน้าจอการตั้งค่าหรือตัวแสดงรูปภาพ ## การจำลอง Light และ Dark Mode ใน DevTools React Native DevTools แนะนำการรองรับ [Emulation.setEmulatedMedia](https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setEmulatedMedia) ทำให้สามารถสลับธีมได้ทันทีโดยไม่ต้องเปลี่ยนการตั้งค่าอุปกรณ์หรือ emulator เข้าถึงฟีเจอร์นี้ผ่าน Command Palette ด้วย `Cmd+Shift+P` (macOS) หรือ `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; } ``` สถานะ media ที่จำลองจะถูกรีเซ็ตเมื่อ DevTools ตัดการเชื่อมต่อ รับประกันว่า build ของ production จะไม่ได้รับผลกระทบจากการทดสอบธีมในระหว่าง development ## คำถามสัมภาษณ์: React Native 0.86 และ Edge-to-Edge การสัมภาษณ์ทางเทคนิคในปี 2026 ให้ความสำคัญกับความเข้ากันได้กับ Android 15 และการใช้งาน edge-to-edge มากขึ้น การเชี่ยวชาญแนวคิดเหล่านี้แสดงให้เห็นถึงความเข้าใจในแนวปฏิบัติการพัฒนา mobile สมัยใหม่ สำหรับการเตรียมตัวสัมภาษณ์อย่างครอบคลุม สามารถสำรวจโมดูล [คำถามสัมภาษณ์ debugging React Native](/technologies/react-native/interview-questions/rn-debugging) ได้ ### โหมด edge-to-edge คืออะไรและทำไม Android 15 ถึงบังคับใช้ โหมด edge-to-edge ขยายเนื้อหาแอปพลิเคชันไปใต้องค์ประกอบ UI ของระบบ (status bar, navigation bar, ตัวบ่งชี้ gesture) Android 15 บังคับใช้พฤติกรรมนี้โดยค่าเริ่มต้นเพื่อให้ประสบการณ์ที่ดื่มด่ำและ UI ที่สอดคล้องกันทั่วทั้งแพลตฟอร์ม แอปพลิเคชันต้องจัดการ safe area insets เพื่อป้องกันเนื้อหาถูกบดบังโดย UI ระบบ ### พฤติกรรม measureInWindow เปลี่ยนแปลงอย่างไรเมื่อ edge-to-edge ถูกเปิดใช้งาน ก่อน React Native 0.86 `measureInWindow` ส่งคืนพิกัดสัมพัทธ์กับหน้าต่างที่มองเห็น ซึ่งไม่รวมพื้นที่ UI ของระบบ เมื่อใช้ edge-to-edge หน้าต่างขยายไปถึงขอบหน้าจอ แต่การวัดไม่ถูกต้องเนื่องจาก offset เวอร์ชัน 0.86 รับประกันว่าพิกัดถูกต้องโดยไม่คำนึงถึงสถานะ edge-to-edge ### Behavior ของ KeyboardAvoidingView ที่แนะนำบน Android 15 คืออะไร ใช้ `behavior="padding"` บน Android 15 เมื่อ edge-to-edge ถูกเปิดใช้งาน Behavior `height` อาจทำให้เกิดการกระโดดของ layout เนื่องจากการคำนวณความสูงที่ใช้งานได้เปลี่ยนแปลงเมื่อ keyboard ปรากฏ Behavior `padding` ให้การเปลี่ยนผ่านที่นุ่มนวลกว่าและการวางตำแหน่งที่คาดเดาได้มากขึ้น ### Safe area insets แตกต่างกันอย่างไรระหว่าง iOS และ Android edge-to-edge บน iOS safe area insets มีมาตั้งแต่ iPhone X สำหรับ notch และ home indicator บน Android edge-to-edge insets รวมถึงความสูงของ status bar, ความสูงของ navigation bar และพื้นที่ตัวบ่งชี้ gesture ไลบรารี `react-native-safe-area-context` ให้ค่า insets ข้ามแพลตฟอร์มผ่าน `useSafeAreaInsets()` ## Pressable android_ripple กับ PlatformColor React Native 0.86 เพิ่มการรองรับ [PlatformColor](https://reactnative.dev/docs/platformcolor) ให้กับ prop `android_ripple` ทำให้สามารถใช้สี ripple แบบไดนามิกที่ตอบสนองต่อการตั้งค่าธีมของระบบ ```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 }, }); ``` การใช้ `?attr/colorControlHighlight` รับประกันว่าสี ripple ตรงตามแนวทาง Material Design และปรับตัวตามธีมสว่าง/มืดที่กำหนดค่าในระดับระบบ ## Image.getSize ส่งคืนขนาดที่ถูกต้อง เมธอด `Image.getSize` และ `Image.getSizeWithHeaders` ตอนนี้ส่งคืนขนาดรูปภาพต้นฉบับแทนค่าที่ถูก downsample การแก้ไขนี้จำเป็นสำหรับการคำนวณ aspect ratio ที่ถูกต้องและ layout รูปภาพแบบ 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%' }, }); ``` การแก้ไขนี้ขจัดความจำเป็นในการใช้ workaround ที่ดึงขนาดรูปภาพผ่าน module native หรือการประมวลผลรูปภาพฝั่ง server ## การจัดการ Response HTTP ขนาดใหญ่โดยไม่เกิด OutOfMemoryError `NetworkingModule` ก่อนหน้านี้โยน `OutOfMemoryError` เมื่อจัดการ response HTTP ขนาดใหญ่ เวอร์ชัน 0.86 ใช้การประมวลผลแบบ chunk สำหรับ response ที่เกินขีดจำกัดหน่วยความจำ ```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 }; } ``` สำหรับการดาวน์โหลดไฟล์ที่เกิน 50MB ควรพิจารณาใช้ [react-native-blob-util](https://github.com/RonRadtke/react-native-blob-util) หรือไลบรารีจัดการไฟล์ native ที่คล้ายกันเพื่อการจัดการหน่วยความจำที่ดีขึ้น ## การแก้ไข Header Cookie ของ WebSocket Header Cookie ที่ส่งผ่าน constructor ของ WebSocket ก่อนหน้านี้ถูกลบก่อนถึง server สิ่งนี้ป้องกันการยืนยันตัวตนแบบ session สำหรับการเชื่อมต่อ 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; } ``` การแก้ไขนี้มีความสำคัญสำหรับแอปพลิเคชันที่ใช้การจัดการ session แบบ cookie ร่วมกับฟีเจอร์ real-time โมดูล [คำถามสัมภาษณ์ networking React Native](/technologies/react-native/interview-questions/rn-networking-api) กล่าวถึง pattern การใช้งาน WebSocket อย่างละเอียด ## สรุป - React Native 0.86 ให้การแก้ไข edge-to-edge ที่จำเป็นสำหรับ Android 15 โดยไม่มี breaking changes - `measureInWindow`, `KeyboardAvoidingView` และ `Dimensions` ทำงานได้อย่างถูกต้องเมื่อ edge-to-edge ถูกเปิดใช้งาน - การอัปเดต StatusBar ตอนนี้มีผลขณะที่ component Modal กำลังแสดงอยู่ - การจำลองธีมของ DevTools เร่งการพัฒนาและทดสอบ dark mode - การรองรับ `PlatformColor` ใน `android_ripple` ทำให้สามารถตอบสนองการสัมผัสตามธีม - `Image.getSize` ส่งคืนขนาดต้นฉบับที่ถูกต้องสำหรับ layout แบบ responsive - Response HTTP ขนาดใหญ่ไม่ทำให้เกิด `OutOfMemoryError` อีกต่อไป - Header Cookie ของ WebSocket ถึง server ตามที่คาดหวัง --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/th/blog/react-native/react-native-086-edge-to-edge-android-devtools-interview-questions