# React Native 면접 질문 30선: 2026 완벽 가이드 > React Native 면접에서 가장 자주 등장하는 30가지 질문을 정리했습니다. 코드 예시가 포함된 상세 답변으로 모바일 개발자 채용에 대비할 수 있습니다. - Published: 2026-02-01 - Updated: 2026-04-27 - Author: SharpSkill - Tags: react native interview, mobile interview, react native questions, javascript, technical interview - Reading time: 20 min --- React Native 기술 면접에서는 크로스 플랫폼 모바일 개발 역량, iOS와 Android 고유 지식, 성능 패턴이 평가됩니다. 본 가이드는 가장 자주 등장하는 30가지 질문을 다루며, 효과적인 준비를 위한 상세 답변과 코드 예시를 함께 제공합니다. > **준비 조언** > > 본 질문들은 기초부터 심화 개념까지 폭넓게 다룹니다. React Native 아키텍처를 이해하고 React 웹과의 차이를 파악하는 것이 면접 성공의 핵심입니다. ## React Native 기초 ### 1. React와 React Native의 차이는 무엇입니까? React는 웹 인터페이스를 구축하는 라이브러리이며, React Native는 iOS와 Android용 네이티브 모바일 앱 개발을 가능하게 합니다. 근본적인 차이는 렌더링 방식에 있습니다. React는 Virtual DOM을 사용해 HTML 요소로 변환하지만, React Native는 브리지를 통해 각 플랫폼의 네이티브 컴포넌트와 통신합니다. ```jsx // React (Web) - uses HTML elements function WebComponent() { return (
Web text
) } // React Native - uses native components import { View, Text, TouchableOpacity, StyleSheet } from 'react-native' function NativeComponent() { return ( Native text Press ) } const styles = StyleSheet.create({ container: { flex: 1, padding: 16 } }) ``` React Native 컴포넌트는 iOS에서 UIView로, Android에서 android.view로 변환되어 네이티브 수준의 성능을 제공합니다. ### 2. React Native의 아키텍처는 어떻게 동작합니까? React Native는 JavaScript, Bridge(신 아키텍처에서는 JSI), Native의 3계층 구조를 사용합니다. JavaScript 코드는 JS 엔진(Hermes 또는 JavaScriptCore)에서 실행됩니다. 네이티브 코드와의 통신은 구 아키텍처에서는 JSON 직렬화를 거치고, 신 아키텍처에서는 JSI(JavaScript Interface)를 통해 직접 이루어집니다. ```jsx // Old architecture: asynchronous communication via Bridge // The Bridge serializes messages as JSON between JS and Native // New architecture (Fabric + TurboModules) // JSI enables synchronous direct calls to native modules // Example TurboModule usage import { TurboModuleRegistry } from 'react-native' // Synchronous access to native module const DeviceInfo = TurboModuleRegistry.get('DeviceInfo') const deviceName = DeviceInfo.getDeviceName() // Synchronous call // With Fabric, rendering is smoother // Components can be created synchronously // Reducing jank during animations ``` 신 아키텍처는 JSON 직렬화를 제거하고 동기 호출을 가능하게 하여 성능을 크게 향상시킵니다. ### 3. Metro 번들러는 무엇입니까? Metro는 React Native에서 사용하는 JavaScript 번들러로, 소스 코드를 모바일 실행에 최적화된 번들로 변환합니다. Metro는 모듈 해석, Babel을 통한 코드 변환, 개발 시점의 핫 리로딩을 처리합니다. ```javascript // metro.config.js const { getDefaultConfig } = require('expo/metro-config') const config = getDefaultConfig(__dirname) // Custom configuration config.resolver.assetExts.push('db') // Add extensions config.resolver.sourceExts.push('cjs') // CommonJS support // Transformer configuration config.transformer.babelTransformerPath = require.resolve( 'react-native-svg-transformer' ) // Production optimizations config.transformer.minifierConfig = { keep_classnames: true, keep_fnames: true, mangle: { keep_classnames: true, keep_fnames: true } } module.exports = config ``` Metro는 Fast Refresh를 지원하여 애플리케이션 상태를 잃지 않고 즉시 변경 사항을 반영합니다. ### 4. StyleSheet.create와 그 이점을 설명해 주십시오 `StyleSheet.create`는 스타일을 검증하고 숫자 참조로 변환하여 최적화하므로 브리지 통신 비용을 줄여 줍니다. ```jsx // ❌ Inline styles - recreated on every render function BadExample() { return ( Title ) } // ✅ StyleSheet.create - optimized and validated const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#fff' }, title: { fontSize: 18, fontWeight: 'bold' }, // Style composition row: { flexDirection: 'row', alignItems: 'center', gap: 8 } }) function GoodExample() { return ( Title {/* Style combination */} Content ) } // StyleSheet.absoluteFillObject for absolute positioning const overlayStyles = StyleSheet.create({ overlay: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.5)' } }) ``` ### 5. 웹 Flexbox와 React Native의 차이는 무엇입니까? React Native도 Flexbox를 사용하지만, 세로 방향의 모바일 화면에 맞춰 웹과 다른 기본값이 적용됩니다. ```jsx // Key differences from web const styles = StyleSheet.create({ container: { // flexDirection: 'column' by default (vs 'row' on web) // alignItems: 'stretch' by default flex: 1 }, // React Native Flexbox row: { flexDirection: 'row', // Horizontal justifyContent: 'space-between', // Main axis alignItems: 'center', // Cross axis flexWrap: 'wrap', // Line wrapping gap: 8 // Supported since RN 0.71 }, // Flex grow/shrink flexItem: { flex: 1, // Equivalent to flex: 1 1 0 flexGrow: 1, // Grow to fill flexShrink: 0, // Don't shrink flexBasis: 100 // Base size }, // Absolute positioning absolute: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 } }) // Practical example: card with image and content function Card() { return ( Title Description ) } const cardStyles = StyleSheet.create({ container: { flexDirection: 'row', backgroundColor: '#fff', borderRadius: 8, overflow: 'hidden' }, image: { width: 100, height: 100 }, content: { flex: 1, // Takes remaining space padding: 12, justifyContent: 'center' }, title: { fontSize: 16, fontWeight: '600' }, description: { fontSize: 14, color: '#666' } }) ``` ## 내비게이션과 컴포넌트 ### 6. React Navigation으로 내비게이션을 어떻게 구현합니까? React Navigation은 React Native의 표준 내비게이션 라이브러리로, 모바일 패턴에 적합한 다양한 내비게이터 유형을 제공합니다. ```jsx // Installing dependencies // npm install @react-navigation/native @react-navigation/native-stack // npm install react-native-screens react-native-safe-area-context import { NavigationContainer } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' // TypeScript typing for navigation params type RootStackParamList = { Home: undefined Profile: { userId: string } Settings: { section?: string } } const Stack = createNativeStackNavigator() const Tab = createBottomTabNavigator() // Tab navigation function TabNavigator() { return ( ({ tabBarIcon: ({ focused, color, size }) => { // Dynamic icon based on tab const iconName = route.name === 'Home' ? 'home' : 'settings' return }, tabBarActiveTintColor: '#007AFF', tabBarInactiveTintColor: 'gray' })} > ) } // Stack navigation function App() { return ( ({ title: `Profile ${route.params.userId}` })} /> ) } ``` ### 7. FlatList로 성능 좋은 리스트를 어떻게 다룹니까? `FlatList`는 자동 가상화를 통해 화면에 보이는 항목만 렌더링하는, 긴 리스트에 최적화된 컴포넌트입니다. ```jsx import { FlatList, RefreshControl } from 'react-native' function ProductList() { const [products, setProducts] = useState([]) const [refreshing, setRefreshing] = useState(false) const [loading, setLoading] = useState(false) // Initial loading const fetchProducts = async (page = 1) => { const response = await api.getProducts(page) return response.data } // Pull-to-refresh const onRefresh = useCallback(async () => { setRefreshing(true) const data = await fetchProducts(1) setProducts(data) setRefreshing(false) }, []) // Infinite pagination const loadMore = useCallback(async () => { if (loading) return setLoading(true) const nextPage = Math.ceil(products.length / 20) + 1 const data = await fetchProducts(nextPage) setProducts(prev => [...prev, ...data]) setLoading(false) }, [products.length, loading]) // Item rendering const renderItem = useCallback(({ item }) => ( ), []) // Key extraction const keyExtractor = useCallback((item) => item.id.toString(), []) // Item separator const ItemSeparator = useCallback(() => ( ), []) return ( } // Infinite pagination onEndReached={loadMore} onEndReachedThreshold={0.5} ListFooterComponent={loading ? : null} // Empty list ListEmptyComponent={} /> ) } ``` > **FlatList 최적화** > > `renderItem`은 반드시 `useCallback`으로 메모화하고 무거운 컴포넌트는 별도로 분리해야 합니다. `renderItem` 내부의 인라인 함수는 불필요한 재렌더링을 유발합니다. ### 8. TouchableOpacity, Pressable, TouchableHighlight의 차이는 무엇입니까? 세 컴포넌트 모두 터치 이벤트를 처리하지만 시각적 피드백 방식이 서로 다릅니다. ```jsx import { TouchableOpacity, TouchableHighlight, Pressable, StyleSheet } from 'react-native' function InteractionExamples() { return ( {/* TouchableOpacity: reduces opacity on touch */} console.log('Pressed')} style={styles.button} > TouchableOpacity {/* TouchableHighlight: adds background color */} console.log('Pressed')} style={styles.button} > TouchableHighlight {/* Pressable: modern API with more control */} console.log('Pressed')} onLongPress={() => console.log('Long press')} delayLongPress={500} style={({ pressed }) => [ styles.button, pressed && styles.buttonPressed ]} > {({ pressed }) => ( {pressed ? 'Pressed!' : 'Pressable'} )} {/* Pressable with hitSlop to enlarge touch area */} console.log('Pressed')} style={styles.smallButton} > Small button ) } const styles = StyleSheet.create({ container: { gap: 16, padding: 20 }, button: { backgroundColor: '#007AFF', padding: 16, borderRadius: 8, alignItems: 'center' }, buttonPressed: { backgroundColor: '#0056b3', transform: [{ scale: 0.98 }] }, textPressed: { color: '#fff' }, smallButton: { padding: 8, backgroundColor: '#eee' } }) ``` 신규 프로젝트에서는 더 세밀한 제어와 일관된 API를 제공하는 `Pressable` 사용이 권장됩니다. ### 9. 부드러운 애니메이션을 어떻게 구현합니까? React Native는 여러 애니메이션 API를 제공합니다. 내장 Animated와 더 높은 성능을 제공하는 Reanimated가 대표적입니다. ```jsx import { Animated, Easing } from 'react-native' import Reanimated, { useSharedValue, useAnimatedStyle, withSpring, withTiming } from 'react-native-reanimated' // Animation with Animated (native API) function FadeInView({ children }) { const fadeAnim = useRef(new Animated.Value(0)).current useEffect(() => { Animated.timing(fadeAnim, { toValue: 1, duration: 500, easing: Easing.ease, useNativeDriver: true // Performant on UI thread }).start() }, []) return ( {children} ) } // Animation with Reanimated (recommended for complex animations) function BouncyButton() { const scale = useSharedValue(1) const animatedStyle = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] })) const handlePressIn = () => { scale.value = withSpring(0.95, { damping: 10, stiffness: 400 }) } const handlePressOut = () => { scale.value = withSpring(1, { damping: 10, stiffness: 400 }) } return ( Press ) } // List animation with LayoutAnimation import { LayoutAnimation, UIManager, Platform } from 'react-native' // Enable on Android if (Platform.OS === 'android') { UIManager.setLayoutAnimationEnabledExperimental?.(true) } function AnimatedList() { const [items, setItems] = useState([]) const addItem = () => { // Configure animation before state change LayoutAnimation.configureNext(LayoutAnimation.Presets.spring) setItems(prev => [...prev, { id: Date.now() }]) } const removeItem = (id) => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) setItems(prev => prev.filter(item => item.id !== id)) } return (