React 미드레벨 CS 기초 면접
새 면접Q. React SPA에서 JWT 토큰 기반 인증을 구현할 때, Access Token과 Refresh Token을 어디에 저장해야 하는지 설명하고, 각 저장 방식(localStorage, sessionStorage, cookie, memory)의 보안 취약점과 트레이드오프를 비교해주세요. 특히 XSS와 CSRF 공격에 대한 방어 관점에서 설명해주세요.
Access Token은 메모리나 httpOnly 쿠키에 저장하는 것이 안전합니다. localStorage는 XSS 공격에 취약하여 스크립트로 토큰을 탈취당할 수 있습니다. Refresh Token은 httpOnly, Secure, SameSite 속성을 가진 쿠키에 저장하여 JavaScript 접근을 차단해야 합니다. 메모리 저장은 XSS에 안전하지만 새로고침 시 토큰이 사라지므로 Refresh Token으로 재발급 로직이 필요합니다. httpOnly 쿠키는 CSRF 공격 위험이 있으므로 CSRF 토큰이나 SameSite 속성으로 방어해야 합니다.
- • localStorage는 XSS 공격에 취약하여 토큰 저장에 부적합
- • httpOnly 쿠키는 JavaScript 접근 차단으로 XSS 방어 가능
- • 메모리 저장은 가장 안전하지만 새로고침 시 손실됨
- • CSRF 방어를 위해 SameSite 속성이나 CSRF 토큰 필요
Token Rotation 전략과 Silent Refresh 패턴을 구현한다면 어떤 방식으로 설계하시겠습니까?
Q. 실시간 검색어 순위를 구현해야 합니다. 사용자의 검색어를 수집하여 상위 N개의 인기 검색어를 빠르게 조회해야 하는데, 이를 위한 효율적인 자료구조와 알고리즘을 제안해주세요. 특히 검색어 카운팅, 정렬, 조회의 시간 복잡도를 고려하여 설명해주세요.
Hash Map과 Min Heap을 조합하여 구현하는 것이 효율적입니다. Hash Map으로 각 검색어의 빈도를 O(1)에 저장하고, 크기가 N인 Min Heap으로 상위 N개를 유지합니다. 새 검색어가 들어올 때 Hash Map을 업데이트하고, 해당 검색어가 힙의 최솟값보다 크면 교체합니다. 이 방식은 삽입 O(log N), 조회 O(N)의 시간 복잡도를 가집니다. 대안으로 Trie 자료구조를 사용하면 prefix 기반 자동완성도 함께 지원할 수 있습니다. 대규모 시스템에서는 Redis의 Sorted Set을 활용하여 분산 환경에서도 효율적으로 처리할 수 있습니다.
- • Hash Map으로 검색어 빈도를 O(1)에 카운팅
- • Min Heap으로 상위 N개를 효율적으로 유지
- • Trie는 자동완성 기능까지 지원 가능
- • Redis Sorted Set은 분산 환경에 적합
실시간으로 검색어 순위가 변동될 때 React 컴포넌트에서 불필요한 리렌더링을 방지하려면 어떻게 구현해야 할까요?
Q. React 애플리케이션에서 페이지네이션을 구현할 때, Offset 기반 페이지네이션과 Cursor 기반 페이지네이션의 차이를 설명하고, 각각의 장단점과 적합한 사용 사례를 데이터베이스 쿼리 성능 관점에서 설명해주세요.
Offset 기반은 LIMIT과 OFFSET을 사용하여 특정 페이지로 직접 이동 가능하지만, 데이터가 많을수록 OFFSET 값만큼 행을 건너뛰어야 해서 성능이 저하됩니다. 또한 데이터 추가/삭제 시 중복이나 누락이 발생할 수 있습니다. Cursor 기반은 마지막 항목의 고유 ID를 기준으로 다음 데이터를 조회하므로 WHERE 절과 인덱스로 O(log N) 성능을 유지하며, 실시간 데이터 변경에 안정적입니다. 그러나 특정 페이지로 직접 점프가 불가능합니다. Offset은 페이지 번호가 필요한 게시판에, Cursor는 무한 스크롤이나 피드에 적합합니다.
- • Offset 방식은 페이지 번호 접근 가능하나 대용량 데이터에서 성능 저하
- • Cursor 방식은 인덱스 활용으로 일정한 성능 유지
- • Cursor는 실시간 데이터 변경에 안정적
- • 사용 사례에 따라 적절한 방식 선택 필요
무한 스크롤에서 사용자가 스크롤을 빠르게 내릴 때 중복 요청을 방지하고 데이터 일관성을 유지하는 전략은 무엇인가요?
Q. 브라우저에서 JavaScript는 싱글 스레드로 동작하는데, Web Worker를 사용하는 이유와 동작 원리를 설명해주세요. React 애플리케이션에서 Web Worker를 활용하면 좋은 사례와, 메인 스레드와 Worker 간 데이터 통신 시 주의해야 할 점을 설명해주세요.
Web Worker는 별도의 백그라운드 스레드에서 JavaScript를 실행하여 CPU 집약적인 작업이 메인 스레드를 블로킹하는 것을 방지합니다. 메인 스레드는 UI 렌더링과 이벤트 처리를 담당하므로, 무거운 계산, 대용량 데이터 파싱, 이미지 처리 등을 Worker로 오프로드하면 UI 반응성을 유지할 수 있습니다. Worker와 메인 스레드는 postMessage로 통신하며, 데이터는 구조화된 복제 알고리즘으로 복사되므로 대용량 데이터 전송 시 오버헤드가 발생합니다. Transferable Objects를 사용하면 복사 없이 소유권을 이전할 수 있습니다. Worker는 DOM 접근이 불가능하므로 순수 계산 작업에만 사용해야 합니다.
- • Web Worker는 CPU 집약 작업을 별도 스레드에서 실행
- • 메인 스레드의 UI 반응성 유지 가능
- • postMessage 통신 시 데이터 복사 오버헤드 주의
- • Transferable Objects로 대용량 데이터 효율적 전달
- • Worker는 DOM 접근 불가
Service Worker와 Web Worker의 차이점은 무엇이며, PWA 구현 시 Service Worker를 어떻게 활용할 수 있나요?
Q. React에서 캐시 시스템을 구현할 때 LRU(Least Recently Used) 캐시를 사용하는 이유와 구현 방법을 설명해주세요. LRU 캐시의 get과 put 연산을 O(1) 시간 복잡도로 구현하기 위해 어떤 자료구조를 조합해야 하는지, 그리고 React Query나 SWR 같은 라이브러리에서 캐시 무효화 전략과 어떻게 연결되는지 설명해주세요.
LRU 캐시는 제한된 메모리에서 가장 오래 사용되지 않은 항목을 제거하여 캐시 히트율을 최적화합니다. O(1) 구현을 위해 Hash Map과 Doubly Linked List를 조합합니다. Hash Map은 키로 노드에 O(1) 접근을 제공하고, Doubly Linked List는 최근 사용 순서를 유지하며 head에 최신, tail에 최구 항목을 배치합니다. get 시 해당 노드를 head로 이동하고, put 시 용량 초과면 tail 노드를 제거합니다. React Query는 staleTime과 cacheTime으로 캐시 수명을 관리하며, LRU 방식으로 메모리를 관리합니다. invalidateQueries로 특정 캐시를 무효화하거나, refetchInterval로 주기적 갱신이 가능합니다.
- • Hash Map으로 O(1) 키 접근, Doubly Linked List로 순서 관리
- • get/put 모두 O(1) 시간 복잡도 달성
- • 최근 사용 항목을 head로, 제거 대상을 tail에 배치
- • React Query는 LRU 기반 캐시와 시간 기반 무효화 전략 조합
- • 메모리 효율성과 캐시 히트율 최적화
LFU(Least Frequently Used) 캐시와 비교했을 때 LRU가 더 적합한 상황은 언제이며, 실제 API 응답 캐싱에서는 어떤 추가 고려사항이 있나요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!