React 미드레벨 CS 기초 면접
새 면접Q. React에서 대량의 데이터를 다룰 때 적절한 자료구조 선택이 성능에 큰 영향을 미칩니다. 배열(Array)과 객체(Object), Map, Set의 시간 복잡도 차이를 설명하고, 각각 어떤 상황에서 사용하는 것이 최적인지 실무 사례와 함께 말씀해주세요. 특히 React state로 관리할 때 고려해야 할 점도 설명해주세요.
배열은 인덱스 접근 O(1), 검색 O(n)이며 순서가 중요한 리스트에 적합합니다. 객체와 Map은 키 기반 접근이 O(1)로 ID 기반 조회가 빈번한 경우 유리하며, Map은 키 타입 제약이 없고 순회 순서가 보장됩니다. Set은 중복 제거와 존재 여부 확인이 O(1)로 빠릅니다. React state에서는 불변성 유지를 위해 배열/객체는 spread 연산이 필요하지만, Map/Set은 new Map(prevMap)으로 복사해야 하며, 일반적으로 직렬화가 쉬운 plain object가 선호됩니다. 대량의 ID 기반 조회가 필요한 경우 normalizing pattern으로 객체를 사용하는 것이 배열 find보다 효율적입니다.
- • 배열은 O(n) 검색, 객체/Map은 O(1) 키 접근으로 조회 패턴에 따라 선택
- • Set은 중복 제거와 존재 확인에 최적화되어 있음
- • React state는 불변성 유지가 필요하며, Map/Set보다 plain object/array가 직렬화와 디버깅에 유리
- • 대량 데이터는 normalized structure(id를 키로 하는 객체)로 관리하면 조회 성능 향상
10만 개의 아이템을 가진 배열에서 특정 ID를 가진 아이템을 자주 업데이트해야 한다면 자료구조를 어떻게 리팩토링하시겠습니까?
Q. 브라우저의 동일 출처 정책(Same-Origin Policy)과 CORS에 대해 설명하고, React SPA에서 API 서버와 통신할 때 CORS 에러가 발생하는 원인과 해결 방법을 설명해주세요. 개발 환경과 프로덕션 환경에서 각각 어떻게 대응해야 하나요?
동일 출처 정책은 프로토콜, 도메인, 포트가 모두 같아야 리소스 접근을 허용하는 보안 정책입니다. React 개발 서버(localhost:3000)와 API 서버(localhost:8000)는 포트가 달라 CORS 에러가 발생합니다. 개발 환경에서는 package.json에 proxy 설정을 추가하거나 webpack devServer의 proxy를 사용하여 우회할 수 있습니다. 프로덕션에서는 API 서버에서 Access-Control-Allow-Origin 헤더를 설정하거나, 같은 도메인에서 서브 경로로 API를 서빙하거나, Nginx 등 리버스 프록시로 라우팅하는 방법이 있습니다. 인증이 필요한 경우 credentials: 'include' 옵션과 서버의 Access-Control-Allow-Credentials 헤더 설정이 필요합니다.
- • Same-Origin Policy는 프로토콜, 도메인, 포트가 모두 같아야 리소스 접근 허용
- • 개발 환경: proxy 설정으로 우회 가능
- • 프로덕션: 서버에서 CORS 헤더 설정 또는 리버스 프록시 사용
- • 쿠키 포함 시 credentials와 서버 설정 모두 필요
preflight request가 무엇이며, 언제 발생하나요? OPTIONS 요청을 줄이기 위한 최적화 방법은 무엇인가요?
Q. React 애플리케이션에서 트리 구조의 데이터(예: 파일 시스템, 조직도, 댓글 스레드)를 렌더링해야 합니다. 재귀적 렌더링과 평탄화(flattening) 후 렌더링 방식의 장단점을 설명하고, 각 방식의 시간 복잡도와 메모리 사용량을 분석해주세요. 또한 깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)을 언제 사용해야 하는지 설명해주세요.
재귀적 렌더링은 코드가 직관적이고 구조를 그대로 반영하지만, 깊은 트리에서 call stack 제한과 각 노드마다 컴포넌트 인스턴스가 생성되어 메모리 오버헤드가 있습니다. 평탄화 방식은 먼저 O(n)으로 배열로 변환 후 단일 루프로 렌더링하여 call stack 문제가 없고 virtualization 적용이 쉽지만, 들여쓰기 표현을 위한 추가 로직이 필요합니다. DFS는 재귀나 스택으로 구현하며 특정 경로 탐색이나 깊이 제한 검색에 적합하고, BFS는 큐로 구현하며 최단 경로나 레벨별 처리에 적합합니다. 대규모 트리는 평탄화 후 react-window로 가상화하는 것이 성능상 유리합니다.
- • 재귀 렌더링: 직관적이나 call stack 제한과 메모리 오버헤드 존재
- • 평탄화 방식: virtualization 적용 용이, 대규모 트리에 유리
- • DFS는 깊이 우선(스택/재귀), BFS는 레벨 우선(큐) 탐색
- • 시간 복잡도는 둘 다 O(n)이지만 공간 복잡도와 렌더링 성능이 다름
무한 스크롤이 가능한 트리 구조를 구현한다면 어떤 방식으로 데이터를 로딩하고 렌더링하시겠습니까?
Q. React 애플리케이션에서 관계형 데이터를 효율적으로 관리하기 위해 데이터 정규화(normalization)를 적용하는 이유와 방법을 설명해주세요. Redux나 상태관리에서 normalized state shape의 장점과, denormalized 데이터를 받았을 때 정규화하는 전략을 설명해주세요.
데이터 정규화는 중복을 제거하고 일관성을 유지하기 위해 엔티티를 ID 기반 객체로 분리하는 것입니다. 예를 들어 posts와 users가 중첩된 구조를 { posts: { byId: {}, allIds: [] }, users: { byId: {} } } 형태로 분리하면 한 사용자 정보 변경 시 여러 곳을 업데이트할 필요가 없습니다. Redux Toolkit의 createEntityAdapter나 normalizr 라이브러리를 사용하면 자동 정규화가 가능합니다. 정규화된 구조는 특정 엔티티 접근이 O(1)로 빠르고 업데이트가 단순하며, 메모이제이션 효율이 높아집니다. API 응답을 정규화할 때는 schema를 정의하고 재귀적으로 엔티티를 추출하여 byId 맵에 저장합니다.
- • 정규화는 중복 제거와 일관성 유지를 위해 ID 기반으로 데이터 분리
- • { entities: { posts: { byId, allIds }, users: { byId } } } 구조 사용
- • 업데이트 단순화, O(1) 접근, 메모이제이션 효율 향상
- • normalizr 또는 createEntityAdapter로 자동화 가능
정규화된 데이터를 컴포넌트에서 사용하기 위해 denormalize하는 과정에서 성능 문제가 발생할 수 있습니다. 이를 어떻게 최적화하시겠습니까?
Q. 브라우저의 이벤트 루프(Event Loop)와 태스크 큐(Task Queue), 마이크로태스크 큐(Microtask Queue)의 동작 원리를 설명하고, React에서 setState 호출 후 실제 DOM 업데이트가 일어나는 시점을 이벤트 루프 관점에서 설명해주세요. Promise와 setTimeout의 실행 순서 차이도 함께 설명해주세요.
이벤트 루프는 콜스택이 비었을 때 태스크 큐에서 작업을 가져와 실행하는 메커니즘입니다. 마이크로태스크 큐(Promise, queueMicrotask)는 각 태스크 실행 직후 콜스택이 비면 즉시 처리되고, 태스크 큐(setTimeout, setInterval)는 모든 마이크로태스크가 처리된 후 실행됩니다. React의 setState는 동기적으로 호출되지만 실제 리렌더링은 batching되어 마이크로태스크 타이밍에 스케줄링됩니다. React 18에서는 자동 batching으로 이벤트 핸들러뿐 아니라 Promise, setTimeout 내부에서도 여러 setState가 한 번에 처리됩니다. Promise.then은 마이크로태스크라 setTimeout보다 먼저 실행되며, 이는 우선순위가 높아 UI 업데이트 전에 처리됩니다.
- • 이벤트 루프: 콜스택 비었을 때 큐에서 작업 실행
- • 마이크로태스크(Promise) > 태스크(setTimeout) 우선순위
- • React setState는 batching되어 마이크로태스크 타이밍에 처리
- • React 18 자동 batching으로 비동기 콜백에서도 일괄 처리
useEffect 내부에서 비동기 작업을 수행할 때 cleanup 함수와 이벤트 루프의 관계를 설명하고, race condition을 방지하는 방법을 말씀해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!