TIL - 프론트엔드 면접 대비 핵심 질문

·2025년 7월 22일

📖 TIL

목록 보기
86/90

🎯 1. Context API vs Redux vs Recoil - 상태관리 도구 비교

🤔 질문

Context API와 Redux, 그리고 Recoil 같은 상태관리 도구의 차이점은 무엇인가요?
언제 Context만으로 충분하고, 언제 외부 상태관리 라이브러리를 써야 할까요?

💡 답변

Context API는 React에서 기본으로 제공하는 전역 상태 관리 도구로, 설정값이나 다크모드, 언어 설정처럼 빈번하게 변경되지 않는 전역 상태를 전달할 때 적합합니다.

Redux중앙 저장소(store)를 기반으로 컴포넌트 간 복잡한 상태 공유, 액션 기반의 상태 전이 로직, 미들웨어 연동이 필요한 경우에 더 유리합니다. 특히 디버깅 도구(Redux DevTools)를 활용한 추적성도 장점이에요.

Recoil은 React 기반의 비교적 가벼운 상태 관리 도구로, 비동기 상태(atom), 파생 상태(selector)를 선언적으로 관리할 수 있고, 컴포넌트 간의 느슨한 의존성을 유지하면서도 전역 상태를 간편하게 다룰 수 있다는 점에서 장점이 있습니다.

📋 언제 사용하면 좋을까?

  • Context API: 프로젝트의 복잡도가 낮고 단순한 전역 공유가 필요한 경우
  • Redux: 규모가 커지면서 상태 간 의존성이 복잡해지는 경우
  • Recoil: 작은 규모 프로젝트에서 React와 자연스러운 통합이 필요한 경우

🧹 2. useEffect 클린업 함수의 필요성

🤔 질문

useEffect에서의 클린업 함수(clean-up function)는 언제 필요하며, 어떤 상황에서 사용하나요?
예시로 setTimeout, 이벤트 리스너, fetch 취소 같은 걸 들어서 설명해보시겠어요?

💡 답변

useEffect에서 클린업 함수는 컴포넌트가 언마운트될 때 실행되는 정리 함수(clean-up)입니다.

주로 setTimeout, setInterval, addEventListener 등 외부 리소스를 사용하는 작업에서는 컴포넌트가 사라질 때 이를 명시적으로 제거하지 않으면 메모리 누수나 원치 않은 동작이 발생할 수 있어요.

🔍 실제 예시들

useEffect(() => {
  // 1. Timer 클린업
  const timer = setTimeout(() => {
    console.log('실행!');
  }, 1000);
  
  return () => clearTimeout(timer); // 클린업!
}, []);

useEffect(() => {
  // 2. 이벤트 리스너 클린업
  const handleScroll = () => console.log('scroll');
  window.addEventListener('scroll', handleScroll);
  
  return () => window.removeEventListener('scroll', handleScroll);
}, []);

useEffect(() => {
  // 3. fetch 요청 취소
  const controller = new AbortController();
  
  fetch('/api/data', { signal: controller.signal })
    .then(response => response.json())
    .catch(err => console.log(err));
  
  return () => controller.abort(); // 요청 취소!
}, []);

예를 들어 타이머를 걸어놓고 컴포넌트를 빠르게 이동하면 이전 타이머가 실행돼 버리는 문제를 막기 위해 clearTimeout을 클린업에서 해주는 거죠!


🔑 3. React에서 key의 중요성

🤔 질문

React에서 리스트를 렌더링할 때 key의 중요성은 무엇인가요?
key가 없거나 index를 key로 썼을 때 생길 수 있는 문제를 설명해보세요.

💡 답변

React에서 key는 리스트 렌더링 시 각 항목을 고유하게 식별하기 위한 값입니다.

내부적으로 React는 Virtual DOM을 기반으로 diff 알고리즘을 수행할 때 key를 기준으로 변경된 항목을 찾고, 해당 항목만 리렌더링합니다.

⚠️ key가 없거나 index를 사용할 때의 문제점

// ❌ 문제가 될 수 있는 경우
{items.map((item, index) => (
  <div key={index}>
    <input value={item.name} />
  </div>
))}

// ✅ 올바른 사용
{items.map(item => (
  <div key={item.id}>
    <input value={item.name} />
  </div>
))}

만약 key가 없거나 index를 key로 사용하게 되면, 아이템의 위치가 바뀌는 경우 불필요한 리렌더링 또는 입력 폼 초기화 같은 예기치 않은 동작이 발생할 수 있습니다.

그래서 가능하면 id고유한 값을 key로 사용하는 것이 바람직합니다! 🎯


🏗️ 4. 렌더링 방식 비교: SSR vs SSG vs CSR

🤔 질문

서버사이드 렌더링(SSR), 정적 사이트 생성(SSG), 클라이언트 사이드 렌더링(CSR)의 차이를 설명해주세요.
각각 언제 쓰는 게 적절한지, Next.js에서 어떻게 구현되는지도 포함해서!

💡 답변

🖥️ SSR (Server-Side Rendering)

서버사이드에서 HTML을 미리 렌더링해서 클라이언트에 전달하는 방식으로, 초기 로딩 속도가 빠르고 SEO에 유리합니다.

Next.js 구현: getServerSideProps 활용

export async function getServerSideProps() {
  const data = await fetchData();
  return { props: { data } };
}

📄 SSG (Static Site Generation)

빌드 시점에 정적으로 HTML을 생성해두는 방식으로, 변경이 적은 페이지(예: 블로그, 회사 소개)에 적합합니다.

Next.js 구현: getStaticProps, getStaticPaths 사용

export async function getStaticProps() {
  const posts = await getPosts();
  return { props: { posts } };
}

🌐 CSR (Client-Side Rendering)

브라우저에서 JS가 실행되고 나서야 콘텐츠가 렌더링되는 방식으로, SEO에는 불리하지만 사용자 경험이 유연해서 로그인 페이지나 대시보드처럼 사용자 중심 인터랙션이 많은 페이지에 적합합니다.

📊 언제 사용하면 좋을까?

방식적합한 사용처장점단점
SSR뉴스, 검색 결과빠른 초기 로딩, 좋은 SEO서버 부하
SSG블로그, 회사 소개매우 빠름, CDN 활용동적 데이터 제한
CSR대시보드, 관리자 페이지유연한 UX느린 초기 로딩, SEO 불리

실제 프로젝트에서는 페이지의 특성에 따라 혼합 렌더링 전략을 사용하는 것이 좋습니다! 🎨


🔄 5. 불변성과 렌더링 최적화

🤔 질문

컴포넌트의 렌더링 최적화를 위해 불변성(immutability)이 중요한 이유는 무엇인가요?
왜 객체를 새로 만들어주는 것이 더 좋은 방법인지, 그리고 shallow compare와도 연결해서 말씀해보세요

💡 답변

React는 상태가 바뀌었는지 확인할 때 얕은 비교(shallow compare)를 사용합니다. 이때 참조값이 바뀌지 않으면 React는 "같은 객체네?"라고 판단해서 렌더링을 하지 않게 됩니다.

🔍 불변성이란?

불변성(immutability)은 "값을 직접 수정하지 않고, 새로운 객체를 만들어서 상태를 바꾼다"는 개념입니다.

// ✅ 불변성 유지
const obj = { a: 1 };
const newObj = { ...obj, a: 2 }; 

// ❌ 불변성 깨짐
const arr = [1, 2];
arr.push(3); // 직접 수정
setState(arr); // 렌더링 안 될 수 있음!

// ✅ 올바른 방법
setState([...arr, 3]);

🧠 Shallow Compare의 작동 원리

const arr1 = [1, 2];
const arr2 = [1, 2];

arr1 === arr2 // false → 새 배열이니까 다르게 인식!

React는 이렇게 ===로 비교해서 "다르면 다시 렌더링하자!" 결정해요.

📋 핵심 개념 정리

개념설명
불변성기존 값을 직접 바꾸지 않고 새로운 객체를 만들어 상태 변경
shallow compare객체의 참조값만 비교해서 바뀐지 감지
중요한 이유리렌더링 최적화와 예측 가능한 상태 관리, 버그 예방!

그래서 기존 객체를 직접 수정하는 방식이 아니라, 새로운 객체를 만들어 상태를 갱신하는 불변성을 지켜야 React가 정확히 변경을 감지하고 필요한 컴포넌트만 리렌더링할 수 있습니다! ⚡

profile
주니어 프론트엔드 성장기 기록기록

0개의 댓글