React Native 주니어 시스템 설계 면접
새 면접Q. React Native 앱에서 비즈니스 로직과 UI 로직을 분리하는 방법에 대해 설명해주세요. 어떤 폴더 구조와 패턴을 사용하시겠습니까?
화면(Screen), 컴포넌트(Component), 비즈니스 로직(Services/Hooks) 레이어를 어떻게 나눌지 생각해보세요.
폴더 구조는 screens, components, hooks, services, utils로 분리합니다. UI 컴포넌트는 props를 받아 렌더링만 담당하고, Custom Hooks에서 상태 관리와 비즈니스 로직을 처리합니다. API 통신은 services 폴더에서 분리하여 재사용성을 높입니다. Screen 컴포넌트는 hooks와 services를 조합하여 전체 화면을 구성하고, 작은 UI 컴포넌트들을 조합합니다. 이렇게 관심사를 분리하면 테스트와 유지보수가 용이해집니다.
- • 폴더 구조를 screens, components, hooks, services로 명확히 분리
- • Custom Hooks를 사용하여 비즈니스 로직과 상태 관리 분리
- • API 통신 로직은 services 레이어로 독립
중대형 앱에서 여러 개발자가 협업할 때 코드 충돌을 줄이고 기능별로 독립적인 개발이 가능하도록 만듭니다.
만약 앱이 커져서 여러 도메인(예: 사용자, 상품, 주문)이 생긴다면 폴더 구조를 어떻게 확장하시겠습니까?
Q. React Native 앱에서 전역 상태 관리가 필요한 경우와 로컬 상태로 충분한 경우를 구분하는 기준은 무엇인가요? 각각의 예시를 들어 설명해주세요.
상태가 여러 화면에서 공유되는지, 데이터의 생명주기가 컴포넌트보다 긴지를 고려해보세요.
전역 상태는 사용자 인증 정보, 테마 설정, 장바구니처럼 여러 화면에서 공유되고 앱 전체 생명주기 동안 유지되어야 하는 데이터에 사용합니다. 로컬 상태는 폼 입력값, 모달 열림/닫힘, 탭 선택 상태처럼 특정 컴포넌트나 화면 내에서만 사용되는 일시적 데이터에 적합합니다. 전역 상태를 남용하면 불필요한 리렌더링과 복잡도가 증가하므로, 기본은 로컬 상태로 시작하고 필요할 때만 전역으로 승격시킵니다. Context API나 Redux 같은 전역 상태 관리 도구는 정말 필요한 데이터에만 사용해야 합니다.
- • 전역 상태: 여러 화면 공유, 앱 생명주기 동안 유지 (인증, 테마, 장바구니)
- • 로컬 상태: 컴포넌트 내부, 일시적 데이터 (폼, 모달, UI 상태)
- • 기본은 로컬 상태로 시작하고 필요시에만 전역으로 승격
불필요한 전역 상태 사용으로 인한 성능 저하를 방지하고, 상태 관리의 복잡도를 적절히 유지할 수 있습니다.
서버에서 받아온 사용자 목록 데이터는 전역 상태로 관리해야 할까요, 아니면 다른 방법이 있을까요?
Q. React Native 앱에서 REST API를 호출하는 서비스 레이어를 설계한다면 어떤 구조로 만들겠습니까? 에러 처리와 인증 토큰 관리는 어떻게 하시겠습니까?
axios 인스턴스의 interceptor 기능과 공통 에러 처리 로직을 생각해보세요.
axios 인스턴스를 생성하여 baseURL, timeout 등 공통 설정을 정의하고, interceptor를 활용해 모든 요청에 인증 토큰을 자동으로 추가합니다. response interceptor에서 401 에러 발생 시 토큰 갱신 로직을 처리하고, 공통 에러는 토스트 메시지로 표시합니다. API 함수들은 도메인별로 분리하여 userAPI, productAPI처럼 모듈화하고, 각 함수는 async/await로 작성하여 try-catch로 에러를 처리합니다. 인증 토큰은 AsyncStorage나 SecureStore에 저장하고, 앱 시작 시 자동으로 로드합니다.
- • axios 인스턴스와 interceptor로 공통 설정 및 인증 토큰 자동 추가
- • response interceptor에서 401 에러 처리 및 토큰 갱신
- • 도메인별 API 모듈 분리 및 AsyncStorage를 통한 토큰 영속화
모든 API 호출에서 반복되는 인증 로직과 에러 처리를 중앙화하여 코드 중복을 제거하고 유지보수성을 높입니다.
여러 API 요청이 동시에 실패했을 때 에러 토스트가 여러 개 뜨는 것을 방지하려면 어떻게 해야 할까요?
Q. 뉴스 피드 앱을 만든다고 가정할 때, 서버에서 받아온 게시글 목록을 어떻게 캐싱하시겠습니까? 캐시 무효화는 언제 해야 할까요?
메모리 캐시와 디스크 캐시의 차이, 그리고 데이터의 신선도(freshness)를 고려해보세요.
React Query나 SWR 같은 라이브러리를 사용하여 메모리 캐시를 구현하고, staleTime을 5분 정도로 설정하여 일정 시간 동안은 캐시된 데이터를 사용합니다. 사용자가 Pull-to-Refresh를 하거나 새 게시글을 작성한 경우 캐시를 무효화하고 최신 데이터를 가져옵니다. 오프라인 지원이 필요하다면 AsyncStorage에 데이터를 저장하여 디스크 캐시로 활용하고, 네트워크 연결 시 백그라운드에서 업데이트합니다. 이미지는 react-native-fast-image 같은 라이브러리로 별도 캐싱 전략을 적용합니다.
- • React Query/SWR로 메모리 캐시 구현 및 staleTime 설정
- • Pull-to-Refresh나 데이터 변경 시 캐시 무효화
- • 오프라인 지원을 위한 AsyncStorage 디스크 캐시 활용
네트워크 요청을 줄여 데이터 사용량과 로딩 시간을 개선하고, 오프라인에서도 앱을 사용할 수 있게 합니다.
무한 스크롤로 게시글을 계속 불러올 때, 메모리 관리는 어떻게 하시겠습니까?
Q. React Navigation을 사용하여 탭 네비게이션과 스택 네비게이션을 조합한 앱 구조를 설계한다면 어떻게 구성하시겠습니까?
하단 탭 각각이 독립적인 스택을 가지는 구조를 생각해보세요.
최상위에 Tab Navigator를 두고, 각 탭마다 독립적인 Stack Navigator를 중첩하여 배치합니다. 예를 들어 홈 탭, 검색 탭, 프로필 탭이 있다면 각각 HomeStack, SearchStack, ProfileStack을 만들어 탭 내에서의 화면 전환을 관리합니다. 이렇게 하면 각 탭의 네비게이션 히스토리가 독립적으로 유지되어 사용자 경험이 자연스럽습니다. 로그인이 필요한 경우 최상위에 조건부 렌더링으로 AuthStack과 MainTab을 분기합니다. 딥링크나 알림을 통한 특정 화면 진입도 네비게이션 구조에 맞춰 설계합니다.
- • Tab Navigator 안에 각 탭별 Stack Navigator 중첩
- • 각 탭의 네비게이션 히스토리 독립 유지
- • 인증 상태에 따른 조건부 네비게이션 분기
대부분의 모바일 앱에서 사용하는 탭 기반 네비게이션 구조를 체계적으로 구현할 수 있습니다.
모달 화면은 어느 레벨의 네비게이터에 배치해야 할까요?
Q. 다국어 지원(i18n)이 필요한 React Native 앱을 설계한다면 어떤 라이브러리를 사용하고, 번역 파일은 어떻게 관리하시겠습니까?
번역 파일의 구조와 언어 변경 시 앱 전체 리렌더링 방법을 고려해보세요.
react-i18next 라이브러리를 사용하여 다국어를 구현하고, 번역 파일은 locales 폴더에 언어별로 분리하여 ko.json, en.json 형태로 관리합니다. 각 번역 파일은 기능별로 네임스페이스를 나눠 common, home, profile처럼 구조화합니다. 사용자가 언어를 변경하면 AsyncStorage에 저장하고, i18n 인스턴스의 changeLanguage를 호출하여 앱 전체를 리렌더링합니다. Context API와 결합하여 현재 언어 상태를 전역으로 관리하고, 번역 키는 상수로 정의하여 오타를 방지합니다. 날짜나 숫자 포맷도 locale에 맞춰 표시합니다.
- • react-i18next 사용 및 언어별 JSON 파일 분리 관리
- • 네임스페이스로 번역 파일 구조화 및 AsyncStorage에 언어 설정 저장
- • Context API로 전역 언어 상태 관리 및 날짜/숫자 포맷 현지화
글로벌 서비스 출시 시 여러 언어를 체계적으로 지원하고, 번역 업데이트를 효율적으로 관리할 수 있습니다.
번역이 누락된 키가 있을 때 어떻게 처리하고 감지할 수 있을까요?
Q. 대량의 상품 목록을 표시하는 이커머스 앱에서 FlatList의 성능을 최적화하기 위한 전략을 설계해주세요. 이미지 로딩, 메모리 관리, 스크롤 성능을 모두 고려해주세요.
FlatList의 props 설정, 컴포넌트 메모이제이션, 이미지 lazy loading을 종합적으로 생각해보세요.
FlatList에 getItemLayout을 구현하여 아이템 높이를 미리 계산하고, windowSize를 조절하여 렌더링되는 아이템 수를 제한합니다. renderItem에 전달되는 컴포넌트는 React.memo로 감싸고, keyExtractor로 고유한 key를 제공하여 불필요한 리렌더링을 방지합니다. 이미지는 react-native-fast-image로 캐싱하고, onViewableItemsChanged를 활용해 화면에 보이는 이미지만 우선 로딩합니다. removeClippedSubviews를 true로 설정하여 화면 밖 컴포넌트를 DOM에서 제거하고, initialNumToRender를 적절히 설정하여 초기 렌더링 성능을 개선합니다. 페이지네이션을 구현하여 한 번에 로드하는 데이터 양을 제한하고, onEndReached로 추가 데이터를 로드합니다.
- • getItemLayout, windowSize, removeClippedSubviews로 FlatList 최적화
- • React.memo와 keyExtractor로 불필요한 리렌더링 방지
- • 이미지 캐싱, lazy loading, 페이지네이션으로 메모리 및 네트워크 최적화
수천 개의 아이템을 표시하는 목록에서 스크롤 끊김 없이 부드러운 사용자 경험을 제공할 수 있습니다.
상품 목록에서 각 아이템의 좋아요 버튼을 누를 때 전체 리스트가 리렌더링되는 것을 방지하려면 어떻게 해야 할까요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!