React Native 0.86 ในปี 2026: Edge-to-Edge Android, DevTools และคำถามสัมภาษณ์
เชี่ยวชาญ React Native 0.86 พร้อมการรองรับ edge-to-edge Android 15, การปรับปรุง DevTools และคำถามสัมภาษณ์เชิงปฏิบัติ คู่มือฉบับสมบูรณ์พร้อมตัวอย่างโค้ด

React Native 0.86 นำเสนอการรองรับ edge-to-edge อย่างครอบคลุมสำหรับ Android 15+ ทำให้เป็นรุ่นที่สองติดต่อกันที่ไม่มี breaking changes เปิดตัวในเดือนมิถุนายน 2026 เวอร์ชันนี้แก้ไขปัญหา API ของ layout และ measurement ที่ถูกกระทบอย่างเงียบ ๆ จากนโยบาย edge-to-edge บังคับของ Android
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
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' },
});Prop collapsable={false} รับประกันว่า View จะรักษา reference ของ native สำหรับการวัด หากไม่มีสิ่งนี้ React Native อาจทำการ optimize View native นั้นออกไป ทำให้ measureInWindow ล้มเหลว
การแก้ไข KeyboardAvoidingView สำหรับ Android 15
Component KeyboardAvoidingView คำนวณพื้นที่ว่างไม่ถูกต้องเมื่อโหมด edge-to-edge ถูกเปิดใช้งาน เวอร์ชัน 0.86 แก้ไขปัญหานี้โดยการนำ insets ของ UI ระบบมาคำนวณในความสูงที่ใช้งานได้
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 },
});บน Android 15 การใช้ behavior="height" มักทำให้เกิดการกระโดดของ layout Behavior padding ให้ animation ที่นุ่มนวลกว่าและการวางตำแหน่งที่คาดเดาได้มากขึ้นเมื่อ edge-to-edge ถูกเปิดใช้งาน
การอัปเดต StatusBar ระหว่างการแสดง Modal
บั๊กที่คงอยู่นานป้องกันการเปลี่ยนแปลง style และ visibility ของ StatusBar ขณะที่ Modal เปิดอยู่ React Native 0.86 แก้ไขปัญหานี้ ทำให้สามารถปรับแต่ง status bar แบบไดนามิกในขั้นตอน modal ได้
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' },
});การแก้ไขนี้มีความสำคัญเป็นพิเศษสำหรับแอปพลิเคชันที่ใช้งานการสลับ dark mode ในขั้นตอน modal เช่น หน้าจอการตั้งค่าหรือตัวแสดงรูปภาพ
พร้อมที่จะพิชิตการสัมภาษณ์ React Native แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
การจำลอง Light และ Dark Mode ใน DevTools
React Native DevTools แนะนำการรองรับ Emulation.setEmulatedMedia ทำให้สามารถสลับธีมได้ทันทีโดยไม่ต้องเปลี่ยนการตั้งค่าอุปกรณ์หรือ emulator เข้าถึงฟีเจอร์นี้ผ่าน Command Palette ด้วย Cmd+Shift+P (macOS) หรือ Ctrl+Shift+P (Windows/Linux)
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;
}สถานะ media ที่จำลองจะถูกรีเซ็ตเมื่อ DevTools ตัดการเชื่อมต่อ รับประกันว่า build ของ production จะไม่ได้รับผลกระทบจากการทดสอบธีมในระหว่าง development
คำถามสัมภาษณ์: React Native 0.86 และ Edge-to-Edge
การสัมภาษณ์ทางเทคนิคในปี 2026 ให้ความสำคัญกับความเข้ากันได้กับ Android 15 และการใช้งาน edge-to-edge มากขึ้น การเชี่ยวชาญแนวคิดเหล่านี้แสดงให้เห็นถึงความเข้าใจในแนวปฏิบัติการพัฒนา mobile สมัยใหม่ สำหรับการเตรียมตัวสัมภาษณ์อย่างครอบคลุม สามารถสำรวจโมดูล คำถามสัมภาษณ์ debugging React Native ได้
โหมด 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 ให้กับ prop android_ripple ทำให้สามารถใช้สี ripple แบบไดนามิกที่ตอบสนองต่อการตั้งค่าธีมของระบบ
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 },
});การใช้ ?attr/colorControlHighlight รับประกันว่าสี ripple ตรงตามแนวทาง Material Design และปรับตัวตามธีมสว่าง/มืดที่กำหนดค่าในระดับระบบ
Image.getSize ส่งคืนขนาดที่ถูกต้อง
เมธอด Image.getSize และ Image.getSizeWithHeaders ตอนนี้ส่งคืนขนาดรูปภาพต้นฉบับแทนค่าที่ถูก downsample การแก้ไขนี้จำเป็นสำหรับการคำนวณ aspect ratio ที่ถูกต้องและ layout รูปภาพแบบ responsive
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%' },
});การแก้ไขนี้ขจัดความจำเป็นในการใช้ workaround ที่ดึงขนาดรูปภาพผ่าน module native หรือการประมวลผลรูปภาพฝั่ง server
การจัดการ Response HTTP ขนาดใหญ่โดยไม่เกิด OutOfMemoryError
NetworkingModule ก่อนหน้านี้โยน OutOfMemoryError เมื่อจัดการ response HTTP ขนาดใหญ่ เวอร์ชัน 0.86 ใช้การประมวลผลแบบ chunk สำหรับ response ที่เกินขีดจำกัดหน่วยความจำ
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 };
}สำหรับการดาวน์โหลดไฟล์ที่เกิน 50MB ควรพิจารณาใช้ react-native-blob-util หรือไลบรารีจัดการไฟล์ native ที่คล้ายกันเพื่อการจัดการหน่วยความจำที่ดีขึ้น
การแก้ไข Header Cookie ของ WebSocket
Header Cookie ที่ส่งผ่าน constructor ของ WebSocket ก่อนหน้านี้ถูกลบก่อนถึง server สิ่งนี้ป้องกันการยืนยันตัวตนแบบ session สำหรับการเชื่อมต่อ WebSocket
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 กล่าวถึง 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 ตามที่คาดหวัง
เริ่มฝึกซ้อมเลย!
ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ
แท็ก
แชร์
บทความที่เกี่ยวข้อง

React Native กับ TypeScript ปี 2026: สถาปัตยกรรม Type-Safe และคำถามสัมภาษณ์งาน
สร้างแอป React Native แบบ type-safe ด้วย TypeScript, Codegen, TurboModules และ Strict TypeScript API ครอบคลุมรูปแบบสถาปัตยกรรม, typed navigation และคำถามสัมภาษณ์งานปี 2026

Expo Router สำหรับ React Native: คู่มือระบบ Navigation แบบ File-Based ฉบับสมบูรณ์
คู่มือฉบับสมบูรณ์สำหรับ Expo Router ใน React Native ครอบคลุมระบบ routing แบบ file-based, การตั้งค่า layout, tab navigation, dynamic routes, modal screens, typed routes, middleware และการป้องกันเส้นทาง พร้อมตัวอย่างโค้ดจริง

React Native New Architecture คู่มือฉบับสมบูรณ์ 2026: Hermes V1, Fabric, TurboModules และ Bridgeless Mode
คู่มือฉบับสมบูรณ์สำหรับ React Native New Architecture ในปี 2026 ครอบคลุม Hermes V1, Fabric Renderer, TurboModules, JSI และ Bridgeless Mode พร้อมตัวอย่างโค้ดและคำถามสัมภาษณ์