Updated:

React 기초 개념

  1. React란 무엇이며, 다른 프레임워크와 비교했을 때 장점은 무엇인가요?

    React는 Facebook에서 개발한 UI 라이브러리로, 컴포넌트 기반 아키텍처를 사용하여 재사용 가능한 UI 요소를 만들 수 있게 해줍니다. 주요 장점으로는 가상 DOM을 통한 효율적인 렌더링, 단방향 데이터 흐름, 선언적 프로그래밍 방식, 큰 생태계와 커뮤니티 등이 있습니다. Angular와 달리 전체 프레임워크가 아닌 UI 라이브러리이며, Vue보다 더 큰 생태계와 기업 지원을 가지고 있습니다.

  2. 가상 DOM이란 무엇이며, 어떻게 작동하나요?

    가상 DOM은 실제 DOM의 가벼운 복사본으로, React가 메모리에 유지하는 객체입니다. React는 상태가 변경될 때 새로운 가상 DOM 트리를 생성하고, 이전 가상 DOM과 비교(diffing)하여 실제로 변경된 부분만 실제 DOM에 적용합니다. 이 과정을 재조정(Reconciliation)이라고 하며, 불필요한 DOM 조작을 최소화하여 성능을 최적화합니다.

  3. JSX란 무엇인가요?

    JSX는 JavaScript XML의 약자로, JavaScript 내에서 HTML과 유사한 마크업을 작성할 수 있게 해주는 문법적 확장입니다. React 컴포넌트의 구조를 직관적으로 표현할 수 있게 해주며, 실제로는 React.createElement() 함수 호출로 변환됩니다. JSX는 선택사항이지만, 대부분의 React 개발자가 사용하는 표준 방식입니다.

  4. 컴포넌트란 무엇이며, 어떤 종류가 있나요?

    컴포넌트는 React 애플리케이션의 기본 구성 요소로, UI의 독립적이고 재사용 가능한 부분입니다. 함수형 컴포넌트와 클래스 컴포넌트 두 가지 유형이 있습니다. 함수형 컴포넌트는 props를 입력으로 받아 JSX를 반환하는 JavaScript 함수이며, Hooks의 도입 이후 더 많이 사용됩니다. 클래스 컴포넌트는 React.Component를 상속받는 ES6 클래스로, 더 많은 기능(생명주기 메서드 등)을 제공하지만 코드가 더 복잡합니다.

  5. Props와 State의 차이점은 무엇인가요?

    Props(속성)는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 읽기 전용 데이터입니다. 컴포넌트는 자신의 props를 수정할 수 없습니다(불변성). 반면, State(상태)는 컴포넌트 내부에서 관리되는 데이터로, 컴포넌트의 생명주기 동안 변경될 수 있습니다. State가 변경되면 컴포넌트가 다시 렌더링됩니다. 간단히 말해, props는 “외부에서 전달받는 데이터”, state는 “내부에서 관리하는 데이터”입니다.

  6. React의 단방향 데이터 흐름이란 무엇인가요?

    React의 단방향 데이터 흐름(one-way data flow)은 데이터가 부모 컴포넌트에서 자식 컴포넌트로만 전달된다는 개념입니다. 자식 컴포넌트는 props를 통해 데이터를 받기만 하고, 직접 수정할 수 없습니다. 자식 컴포넌트가 데이터를 변경하려면 부모 컴포넌트에서 전달받은 콜백 함수를 호출해야 합니다. 이 패턴은 애플리케이션의 데이터 흐름을 예측 가능하게 만들고, 디버깅을 용이하게 합니다.

  7. 제어 컴포넌트와 비제어 컴포넌트의 차이점은 무엇인가요?

    제어 컴포넌트(Controlled Component)는 React 상태에 의해 값이 제어되는 폼 요소입니다. 입력값이 변경될 때마다 상태가 업데이트되고, 렌더링에 반영됩니다. 비제어 컴포넌트(Uncontrolled Component)는 DOM 자체에 의해 값이 관리되는 폼 요소로, React에서는 ref를 사용하여 필요할 때만 DOM에서 값을 가져옵니다. 제어 컴포넌트는 더 많은 제어와 유효성 검사를 제공하지만, 비제어 컴포넌트는 더 간단하고 특정 상황(파일 입력 등)에 유용할 수 있습니다.

Hooks와 상태 관리

  1. React Hooks란 무엇이며, 왜 도입되었나요?

    React Hooks는 함수형 컴포넌트에서 상태와 생명주기 기능을 사용할 수 있게 해주는 함수들입니다. React 16.8에서 도입되었으며, 클래스 컴포넌트 없이도 React의 모든 기능을 사용할 수 있게 해줍니다. Hooks가 도입된 주요 이유는 컴포넌트 간 상태 로직 재사용의 어려움, 복잡한 컴포넌트의 이해 어려움, 클래스의 혼란스러운 개념(this 바인딩 등) 등의 문제를 해결하기 위함입니다.

  2. 자주 사용되는 Hooks와 그 용도를 설명해주세요.

  • useState: 함수형 컴포넌트에서 상태 관리
  • useEffect: 부수 효과 처리 (데이터 페칭, 구독, DOM 조작 등)
  • useContext: Context API를 통한 전역 상태 접근
  • useReducer: 복잡한 상태 로직 관리
  • useCallback: 함수 메모이제이션
  • useMemo: 계산 결과 메모이제이션
  • useRef: DOM 요소 참조 또는 렌더링 사이에 값 유지
  • useLayoutEffect: DOM 변경 후, 브라우저 페인팅 전에 실행되는 효과
  • useImperativeHandle: ref로 노출되는 인스턴스 값 사용자 정의
  • useDebugValue: 개발자 도구에서 커스텀 Hook 레이블 표시
  1. useEffect의 작동 방식과 의존성 배열의 역할은 무엇인가요?

    useEffect는 컴포넌트 렌더링 후에 부수 효과를 실행하는 Hook입니다. 첫 번째 인자로 효과 함수를, 두 번째 인자로 의존성 배열을 받습니다. 의존성 배열은 효과가 다시 실행되어야 하는 조건을 지정합니다: - 빈 배열([])을 전달하면 컴포넌트 마운트 시에만 효과 실행 - 특정 값을 포함하면 해당 값이 변경될 때마다 효과 실행 - 배열을 생략하면 모든 렌더링 후에 효과 실행

    효과 함수에서 정리(cleanup) 함수를 반환하면, 컴포넌트 언마운트 시 또는 다음 효과 실행 전에 호출됩니다.

  2. 커스텀 Hook이란 무엇이며, 어떤 경우에 사용하나요?

    커스텀 Hook은 로직을 재사용 가능한 함수로 추출한 것으로, 이름이 “use”로 시작하는 JavaScript 함수입니다. 내부에서 다른 React Hook을 사용할 수 있으며, 여러 컴포넌트에서 동일한 상태 로직을 공유할 때 유용합니다. 예를 들어, 데이터 페칭, 폼 처리, 애니메이션 등의 로직을 커스텀 Hook으로 추출하여 재사용할 수 있습니다.

  3. Context API란 무엇이며, 언제 사용해야 하나요?

    Context API는 컴포넌트 트리 전체에 데이터를 전달하는 방법으로, props drilling(여러 단계의 컴포넌트를 통해 props를 전달하는 것) 없이 데이터를 공유할 수 있게 해줍니다. createContext, Provider, useContext로 구성되며, 테마, 로그인 상태, 언어 설정 등 여러 컴포넌트에서 필요한 전역 데이터에 적합합니다. 그러나 자주 변경되는 상태나 복잡한 상태 로직에는 Redux나 다른 상태 관리 라이브러리가 더 적합할 수 있습니다.

  4. Redux와 같은 상태 관리 라이브러리가 필요한 이유는 무엇인가요?

    Redux와 같은 상태 관리 라이브러리는 다음과 같은 경우에 유용합니다: - 애플리케이션 전체에서 공유되는 복잡한 상태 관리 - 깊은 컴포넌트 트리에서의 상태 전달 간소화 - 예측 가능한 상태 업데이트 (순수 함수인 리듀서 사용) - 시간 여행 디버깅, 상태 지속성, 미들웨어 등의 고급 기능 - 상태 변경 로직과 UI 로직의 분리

    작은 애플리케이션에서는 Context API와 useReducer로 충분할 수 있지만, 규모가 커지고 상태 관리가 복잡해질수록 전용 라이브러리의 이점이 커집니다.

성능 최적화

  1. React에서 성능을 최적화하는 방법에는 어떤 것들이 있나요?

    React 애플리케이션의 성능 최적화 방법: - React.memo로 불필요한 리렌더링 방지 - useMemouseCallback으로 계산 비용이 많이 드는 연산이나 함수 메모이제이션 - 상태 구조 최적화 (정규화된 상태, 불변성 유지) - 가상화(virtualization)로 대량의 데이터 효율적 렌더링 - 코드 분할(Code Splitting)과 지연 로딩(Lazy Loading) - 이미지와 자산 최적화 - 서버 사이드 렌더링(SSR) 또는 정적 사이트 생성(SSG) 활용 - 웹 워커를 사용한 무거운 계산 오프로딩 - 효율적인 이벤트 핸들러 관리 (이벤트 위임 등)

  2. React.memo, useMemo, useCallback의 차이점은 무엇인가요?

  • React.memo: 고차 컴포넌트(HOC)로, props가 변경되지 않으면 컴포넌트의 리렌더링을 방지합니다.
  • useMemo: Hook으로, 의존성 배열의 값이 변경될 때만 계산 비용이 많이 드는 값을 재계산합니다.
  • useCallback: Hook으로, 의존성 배열의 값이 변경될 때만 함수를 재생성합니다.

    React.memo는 컴포넌트 자체를 메모이제이션하는 반면, useMemo는 값을, useCallback은 함수를 메모이제이션합니다. useCallback(fn, deps)useMemo(() => fn, deps)와 동일합니다.

  1. 불필요한 리렌더링을 방지하는 방법은 무엇인가요?

    불필요한 리렌더링 방지 방법: - 컴포넌트 분할: 상태 변경의 영향을 받는 부분만 분리 - React.memo로 함수형 컴포넌트 메모이제이션 - shouldComponentUpdate 또는 PureComponent 사용 (클래스 컴포넌트) - useMemouseCallback으로 props로 전달되는 객체와 함수 메모이제이션 - 상태 업데이트 최적화 (불필요한 상태 업데이트 방지) - Context 분할: 자주 변경되는 값과 그렇지 않은 값 분리 - 키(key) 속성 올바르게 사용: 리스트 렌더링 시 안정적인 고유 키 제공

  2. React에서 대량의 데이터를 효율적으로 렌더링하는 방법은 무엇인가요?

    대량 데이터 효율적 렌더링 방법: - 가상화(Virtualization): 화면에 보이는 항목만 렌더링 (react-window, react-virtualized 등 사용) - 페이지네이션: 한 번에 일부 데이터만 로드 및 표시 - 무한 스크롤: 사용자가 스크롤할 때 추가 데이터 로드 - 데이터 정규화: 중복 없이 효율적인 상태 구조 유지 - 메모이제이션: 계산 비용이 많이 드는 변환이나 필터링 최적화 - 지연 로딩: 필요할 때만 컴포넌트나 데이터 로드 - 웹 워커: 무거운 데이터 처리를 별도 스레드로 오프로딩

아키텍처와 패턴

  1. 컴포넌트 구성(Composition)이란 무엇이며, 상속보다 선호되는 이유는 무엇인가요?

    컴포넌트 구성은 여러 컴포넌트를 조합하여 새로운 컴포넌트를 만드는 방식입니다. React에서는 children props나 특정 props를 통해 구성을 구현합니다. 상속보다 구성이 선호되는 이유는: - 더 유연하고 명시적인 코드 작성 가능 - 컴포넌트 간 결합도 감소 - 기능 재사용성 향상 - 테스트와 디버깅이 더 쉬움 - React의 단방향 데이터 흐름 모델과 더 잘 맞음

    React 팀은 수천 개의 컴포넌트를 사용하면서도 컴포넌트 상속을 권장할 사례를 찾지 못했다고 언급했습니다.

  2. 고차 컴포넌트(HOC)란 무엇이며, 언제 사용하나요?

    고차 컴포넌트(Higher-Order Component, HOC)는 컴포넌트를 인자로 받아 새 컴포넌트를 반환하는 함수입니다. 이는 컴포넌트 로직을 재사용하기 위한 React의 고급 패턴입니다. HOC는 다음과 같은 경우에 유용합니다: - 여러 컴포넌트에서 공통 기능 공유 (인증, 데이터 구독 등) - 크로스커팅 관심사(cross-cutting concerns) 분리 - 기존 컴포넌트 기능 확장 - 조건부 렌더링 로직 추상화

    예: withRouter, connect (Redux), withStyles 등이 HOC 패턴을 사용합니다.

  3. Render Props 패턴이란 무엇인가요?

    Render Props는 컴포넌트 간에 값을 공유하기 위해 함수 props를 사용하는 패턴입니다. 이 함수는 컴포넌트가 무엇을 렌더링할지 결정하는 데 사용됩니다. 일반적으로 render 또는 children prop으로 함수를 전달합니다. 이 패턴은 다음과 같은 경우에 유용합니다: - 상태나 동작을 캡슐화하면서 렌더링 로직을 유연하게 제어 - 컴포넌트 간 코드 재사용 - HOC의 대안으로 사용 (중첩 구조 없이 기능 공유)

    예: <Route render={(props) => <MyComponent {...props} />} /> (React Router)

  4. Flux 아키텍처와 Redux의 관계는 무엇인가요?

    Flux는 Facebook이 제안한 애플리케이션 아키텍처로, 단방향 데이터 흐름을 강조합니다. Redux는 Flux의 개념을 기반으로 하지만, 몇 가지 차이점이 있습니다:

    공통점: - 단방향 데이터 흐름 - 액션을 통한 상태 변경 - 상태의 중앙 집중화

    차이점: - Flux는 여러 스토어를 가질 수 있지만, Redux는 단일 스토어 사용 - Redux는 리듀서(순수 함수)를 사용하여 상태 업데이트, Flux는 각 스토어가 자체 로직 포함 - Redux는 불변성 강조 - Redux는 미들웨어 시스템 제공

    Redux는 Flux의 구현체라기보다 Flux 패턴에서 영감을 받은 라이브러리입니다.

  5. Container와 Presentational 컴포넌트 패턴이란 무엇인가요?

    Container/Presentational 패턴은 관심사 분리를 위한 컴포넌트 설계 방식입니다:

  • Container 컴포넌트:
    • 데이터 페칭, 상태 관리, 비즈니스 로직 처리
    • Redux 등의 상태 관리 라이브러리와 연결
    • 일반적으로 스타일링 없음
    • “어떻게 동작하는지”에 집중
  • Presentational 컴포넌트:
    • UI 렌더링에만 집중
    • props를 통해 데이터와 콜백 함수 받음
    • 자체 상태는 UI 상태만 관리 (있는 경우)
    • 재사용 가능하고 스타일링 포함
    • “어떻게 보이는지”에 집중

    Hooks의 등장으로 이 패턴의 필요성이 줄었지만, 여전히 큰 애플리케이션에서 유용한 구조화 방법입니다.

라우팅과 서버 통신

  1. 클라이언트 사이드 라우팅이란 무엇이며, React에서 어떻게 구현하나요?

    클라이언트 사이드 라우팅은 페이지 전체를 다시 로드하지 않고 JavaScript를 사용하여 URL 변경에 따라 화면을 업데이트하는 방식입니다. 이는 더 나은 사용자 경험과 성능을 제공합니다. React에서는 주로 React Router 라이브러리를 사용하여 구현합니다:

    import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
        
    function App() {
      return (
        <BrowserRouter>
          <nav>
            <Link to="/">Home</Link>
            <Link to="/about">About</Link>
          </nav>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
            <Route path="/users/:userId" element={<UserDetail />} />
          </Routes>
        </BrowserRouter>
      );
    }
    

    React Router는 BrowserRouter, Routes, Route, Link 등의 컴포넌트와 useParams, useNavigate, useLocation 같은 Hooks를 제공합니다.

  2. React에서 API 호출을 처리하는 가장 좋은 방법은 무엇인가요?

    React에서 API 호출을 처리하는 방법:

  3. useEffect Hook 내에서 API 호출:
    useEffect(() => {
      const fetchData = async () => {
        try {
          setLoading(true);
          const response = await fetch(url);
          const data = await response.json();
          setData(data);
        } catch (error) {
          setError(error);
        } finally {
          setLoading(false);
        }
      };
           
      fetchData();
    }, [url]);
    
  4. 커스텀 Hook으로 API 로직 추출:
    function useFetch(url) {
      const [data, setData] = useState(null);
      const [loading, setLoading] = useState(true);
      const [error, setError] = useState(null);
           
      useEffect(() => {
        // 페칭 로직
      }, [url]);
           
      return { data, loading, error };
    }
    
  5. React Query, SWR 같은 데이터 페칭 라이브러리 사용:
    const { data, isLoading, error } = useQuery(['users', userId], 
      () => fetchUser(userId)
    );
    
  6. Redux와 미들웨어(Redux Thunk, Redux Saga) 사용

  7. React 18의 Suspense for Data Fetching 활용
최근에는 React Query나 SWR 같은 라이브러리가 캐싱, 재시도, 백그라운드 업데이트 등의 기능을 제공하여 널리 사용됩니다.
  1. 서버 사이드 렌더링(SSR)이란 무엇이며, 어떤 이점이 있나요?

    서버 사이드 렌더링(SSR)은 서버에서 React 컴포넌트를 HTML로 렌더링하여 클라이언트에 전송하는 기술입니다. 이후 클라이언트에서 JavaScript가 로드되면 이 HTML에 이벤트 리스너를 연결하는 “하이드레이션(hydration)” 과정이 진행됩니다.

    SSR의 이점: - 더 빠른 초기 로딩 및 First Contentful Paint (FCP) - 검색 엔진 최적화(SEO) 개선 - 소셜 미디어 공유 시 메타데이터 제공 - 느린 기기나 네트워크에서 더 나은 사용자 경험 - 접근성 향상

    Next.js, Remix 같은 프레임워크는 React 애플리케이션의 SSR을 쉽게 구현할 수 있게 해줍니다.

  2. React Query나 SWR 같은 데이터 페칭 라이브러리의 장점은 무엇인가요?

    데이터 페칭 라이브러리의 장점: - 캐싱: 동일한 데이터에 대한 중복 요청 방지 - 자동 재검증: 포커스, 네트워크 재연결 등의 이벤트 시 데이터 갱신 - 낙관적 업데이트: UI를 즉시 업데이트하고 서버 응답 후 확인 - 페이지네이션 및 무한 스크롤 지원 - 요청 중복 제거 및 재시도 로직 - 백그라운드 업데이트: 오래된 데이터 표시 후 새 데이터로 업데이트 - 서버 상태와 클라이언트 상태의 명확한 구분 - 로딩 및 오류 상태 관리 간소화 - 의존적 쿼리: 다른 쿼리 결과에 따라 쿼리 실행

    이러한 라이브러리는 복잡한 데이터 페칭 로직을 추상화하여 개발자가 비즈니스 로직에 집중할 수 있게 해줍니다.

테스팅과 디버깅

  1. React 컴포넌트를 테스트하는 방법에는 어떤 것들이 있나요?

    React 컴포넌트 테스트 방법:

  2. 단위 테스트: - Jest + React Testing Library 또는 Enzyme 사용 - 컴포넌트의 렌더링, 이벤트 처리, 상태 변경 등 테스트
    test('increments counter when button is clicked', () => {
      render(<Counter />);
      const button = screen.getByText('Increment');
      fireEvent.click(button);
      expect(screen.getByText('Count: 1')).toBeInTheDocument();
    });
    
  3. 통합 테스트: - 여러 컴포넌트의 상호작용 테스트 - 실제 API 대신 모의(mock) 서비스 사용

  4. 스냅샷 테스트: - 컴포넌트 출력의 스냅샷을 저장하고 변경 사항 감지
    test('renders correctly', () => {
      const tree = renderer.create(<Button>Click me</Button>).toJSON();
      expect(tree).toMatchSnapshot();
    });
    
  5. E2E(End-to-End) 테스트: - Cypress, Playwright, Selenium 등 사용 - 실제 브라우저에서 사용자 흐름 테스트

  6. 시각적 회귀 테스트: - Storybook + Chromatic 등 사용 - UI 변경 사항 시각적으로 감지

  7. React 애플리케이션에서 일반적인 성능 문제를 디버깅하는 방법은 무엇인가요?

    React 성능 문제 디버깅 방법:

  8. React DevTools Profiler 사용: - 컴포넌트 렌더링 시간 측정 - 불필요한 리렌더링 식별 - 커밋 간 변경 사항 확인

  9. Chrome DevTools Performance 탭: - JavaScript 실행 시간 분석 - 메모리 사용량 모니터링 - 병목 현상 식별

  10. why-did-you-render 라이브러리: - 불필요한 리렌더링 자동 감지 및 로깅

  11. 코드 분할 분석: - 번들 크기 분석 (webpack-bundle-analyzer) - 큰 번들 식별 및 분할

  12. 메모리 누수 확인:
    • Chrome DevTools Memory 탭
    • 컴포넌트 언마운트 후 이벤트 리스너나 타이머가 정리되지 않는지 확인
  13. 네트워크 요청 최적화:
    • Network 탭에서 불필요하거나 중복된 요청 식별
    • 큰 페이로드 확인
  14. 로깅 및 에러 추적:
    • 콘솔 로그 및 에러 모니터링
    • Sentry 같은 도구로 프로덕션 에러 추적
  15. React에서 발생하는 메모리 누수의 일반적인 원인과 해결 방법은 무엇인가요?

    React 메모리 누수 원인과 해결 방법:

  16. 정리되지 않은 이벤트 리스너:
    useEffect(() => {
      window.addEventListener('resize', handleResize);
           
      // 정리 함수 반환
      return () => {
        window.removeEventListener('resize', handleResize);
      };
    }, []);
    
  17. 취소되지 않은 API 요청:
    useEffect(() => {
      let isMounted = true;
      const fetchData = async () => {
        const response = await fetch(url);
        const data = await response.json();
        if (isMounted) setData(data);
      };
           
      fetchData();
           
      return () => {
        isMounted = false;
      };
    }, [url]);
    
  18. 정리되지 않은 타이머:
    useEffect(() => {
      const timerId = setInterval(() => {
        // 작업 수행
      }, 1000);
           
      return () => {
        clearInterval(timerId);
      };
    }, []);
    
  19. 클로저로 인한 오래된 참조: - 최신 값을 참조하기 위해 useRef 또는 함수형 업데이트 사용

  20. 순환 참조 구조: - 객체 간 순환 참조 피하기 - WeakMap/WeakSet 사용 고려

  21. React 애플리케이션에서 접근성(a11y)을 개선하는 방법은 무엇인가요?

    React 접근성 개선 방법:

  22. 시맨틱 HTML 사용: - <div> 대신 <button>, <a>, <nav> 등 적절한 요소 사용 - ARIA 속성 올바르게 적용

  23. 키보드 접근성: - 모든 상호작용 요소가 키보드로 접근 가능하게 함 - 포커스 관리 및 포커스 트랩 구현
    const modalRef = useRef();
    useEffect(() => {
      modalRef.current?.focus();
    }, [isOpen]);
    
  24. 색상 대비 및 텍스트 크기: - WCAG 지침 준수 - 충분한 색상 대비 제공

  25. 스크린 리더 지원: - 이미지에 대체 텍스트 제공 - 상태 변경 시 적절한 알림
    <img src="logo.png" alt="Company Logo" />
    <div aria-live="polite">{statusMessage}</div>
    
  26. 도구 활용: - ESLint의 jsx-a11y 플러그인 - Lighthouse, axe 등의 접근성 감사 도구 - React Testing Library의 접근성 중심 쿼리

  27. 폼 레이블 및 오류 메시지: - 모든 입력 필드에 레이블 연결 - 오류 메시지를 프로그래밍 방식으로 연결
    <label htmlFor="name">Name:</label>
    <input id="name" aria-describedby="name-error" />
    <div id="name-error">{errors.name}</div>
    

최신 트렌드와 고급 개념

  1. React 18의 주요 새 기능은 무엇인가요?

    React 18의 주요 기능:

  2. 자동 배치 처리 개선: - 이벤트 핸들러 외부에서도 상태 업데이트 배치 처리

  3. 동시성(Concurrency) 기능: - useTransition: 우선순위가 낮은 상태 업데이트 표시 - useDeferredValue: 값의 업데이트를 지연시켜 UI 응답성 유지

  4. 서버 컴포넌트: - 서버에서만 실행되는 컴포넌트로 번들 크기 감소 - 서버 리소스에 직접 접근 가능

  5. Suspense 개선: - 데이터 페칭을 위한 Suspense 지원 - SSR에서 Suspense 지원

  6. 새로운 Hooks: - useId: 접근성을 위한 고유 ID 생성 - useSyncExternalStore: 외부 스토어와 동기화 - useInsertionEffect: CSS-in-JS 라이브러리용

  7. 새로운 Root API: - createRoot를 통한 새로운 렌더링 방식

  8. Strict Mode 개선: - 개발 모드에서 컴포넌트 이중 마운트로 부작용 감지

  9. 서버 컴포넌트란 무엇이며, 어떤 이점이 있나요?

    서버 컴포넌트는 서버에서만 실행되고 클라이언트로 HTML 결과만 전송되는 새로운 유형의 React 컴포넌트입니다. 주요 이점:

  10. 번들 크기 감소: - 서버 컴포넌트의 코드는 클라이언트로 전송되지 않음 - 큰 의존성을 서버에만 유지 가능

  11. 서버 리소스 직접 접근: - 데이터베이스, 파일 시스템 등에 직접 접근 - API 호출 감소

  12. 자동 코드 분할: - 클라이언트 컴포넌트만 자동으로 코드 분할

  13. 향상된 보안: - 민감한 로직이나 API 키를 클라이언트에 노출하지 않음

  14. 초기 로딩 성능 향상: - 데이터를 미리 가져와 HTML에 포함

서버 컴포넌트는 Next.js 같은 프레임워크에서 구현되어 있으며, 클라이언트 컴포넌트와 함께 사용하여 하이브리드 애플리케이션을 구축할 수 있습니다.
  1. React의 동시성(Concurrency) 모드란 무엇인가요?

    동시성 모드는 React 18에서 도입된 새로운 렌더링 모델로, React가 렌더링 작업을 중단, 재개, 우선순위 지정할 수 있게 해줍니다. 주요 특징:

  2. 렌더링 작업 우선순위 지정: - 중요한 업데이트(타이핑, 클릭)를 우선 처리 - 덜 중요한 업데이트(데이터 로딩, 목록 필터링)는 지연 가능

  3. 주요 API: - useTransition: 우선순위가 낮은 상태 업데이트 표시 - startTransition: 함수를 트랜지션으로 표시 - useDeferredValue: 값의 업데이트를 지연

  4. 이점: - UI 응답성 향상 - 사용자 상호작용 차단 방지 - 불필요한 로딩 상태 감소

  5. 사용 예:
    const [isPending, startTransition] = useTransition();
         
    const handleChange = (e) => {
      // 즉시 업데이트 (높은 우선순위)
      setInputValue(e.target.value);
           
      // 트랜지션으로 표시 (낮은 우선순위)
      startTransition(() => {
        setSearchResults(filterItems(e.target.value));
      });
    };
    
  6. React 애플리케이션에서 상태 관리의 최신 트렌드는 무엇인가요?

    React 상태 관리 최신 트렌드:

  7. 상태 관리 간소화: - 거대한 전역 스토어 대신 작은 상태 조각 사용 - Context API + useReducer 조합

  8. 서버 상태와 클라이언트 상태 분리: - React Query, SWR 등으로 서버 상태 관리 - 로컬 UI 상태는 useState, useReducer로 관리

  9. 원자적 상태 관리: - Recoil, Jotai 등의 원자 기반 라이브러리 - 작은 상태 단위로 분할하여 재렌더링 최적화

  10. Redux 간소화: - Redux Toolkit 사용으로 보일러플레이트 감소 - RTK Query로 데이터 페칭 통합

  11. 불변성 관리 간소화: - Immer 통합으로 불변성 유지 코드 간소화

  12. 상태 관리 라이브러리 경량화: - Zustand, Valtio 같은 경량 라이브러리 인기

  13. 상태 지속성 및 동기화: - 로컬 스토리지, IndexedDB와 상태 동기화 - 실시간 협업을 위한 CRDT 기반 상태 관리

  14. TypeScript와 React를 함께 사용할 때의 이점과 모범 사례는 무엇인가요?

    TypeScript와 React 사용 이점:

  15. 타입 안전성: - 컴파일 시점에 오류 발견 - props, 상태, 이벤트 핸들러 등의 타입 검증

  16. 개발자 경험 향상: - 자동 완성 및 인텔리센스 - 리팩토링 용이성

  17. 문서화 효과: - 컴포넌트 인터페이스 명확화 - 팀 협업 개선
모범 사례:
  1. Props 타입 정의:
    interface ButtonProps {
      text: string;
      onClick: () => void;
      variant?: 'primary' | 'secondary';
    }
         
    const Button: React.FC<ButtonProps> = ({ text, onClick, variant = 'primary' }) => {
      // ...
    };
    
  2. 이벤트 핸들러 타입:
    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      // ...
    };
    
  3. 제네릭 컴포넌트:
    interface ListProps<T> {
      items: T[];
      renderItem: (item: T) => React.ReactNode;
    }
         
    function List<T>({ items, renderItem }: ListProps<T>) {
      // ...
    }
    
  4. 타입 추론 활용: - 불필요한 타입 어노테이션 피하기 - useState와 같은 제네릭 Hook 활용

  5. 유틸리티 타입 사용: - Partial, Pick, Omit 등으로 타입 조작 - 중복 타입 정의 최소화

  6. 마이크로 프론트엔드 아키텍처에서 React를 어떻게 활용할 수 있나요?

    마이크로 프론트엔드와 React:

  7. 마이크로 프론트엔드 접근 방식: - 웹 애플리케이션을 독립적으로 개발, 테스트, 배포할 수 있는 작은 앱으로 분할 - 각 팀이 자체 기술 스택, 릴리스 주기 가능

  8. React 기반 구현 방법: (계속)
    • Web Components 래핑: ```jsx class ReactWrapper extends HTMLElement { connectedCallback() { const mountPoint = document.createElement(‘div’); this.attachShadow({ mode: ‘open’ }).appendChild(mountPoint);

      ReactDOM.render(, mountPoint); }

    disconnectedCallback() { ReactDOM.unmountComponentAtNode(this.shadowRoot); } }

    customElements.define(‘react-component’, ReactWrapper); ```

  • iframes 사용
  • 서버 사이드 조합 (SSI, ESI 등)
  • 런타임 통합 라이브러리 (single-spa, qiankun 등)
  1. 통합 과제 해결:
    • 스타일 격리: CSS Modules, CSS-in-JS, Shadow DOM
    • 상태 공유: 이벤트 버스, 공유 라이브러리, 쿠키/localStorage
    • 라우팅 조정: 중앙 라우터 또는 라우터 통합
    • 성능 최적화: 공통 의존성 공유, 코드 분할
  2. 모노레포 관리:
    • Nx, Lerna, Turborepo 등으로 코드베이스 관리
    • 공유 컴포넌트 라이브러리 구축

실무 및 프로젝트 관련

  1. 대규모 React 애플리케이션을 구조화하는 방법은 무엇인가요?

    대규모 React 애플리케이션 구조화:

  2. 폴더 구조 전략: - 기능별 구조 (Feature-based):

     /src
       /features
         /auth
           /components
           /hooks
           /services
           /store
           index.js
         /products
           /components
           /hooks
           /services
           /store
           index.js
       /shared
         /components
         /hooks
         /utils
    
- 계층별 구조 (Layer-based):
  ```
  /src
    /components
      /common
      /layout
      /features
    /hooks
    /services
    /store
    /utils
  ```
  1. 코드 분할 및 지연 로딩:
    const ProductDetails = React.lazy(() => import('./features/products/ProductDetails'));
         
    function App() {
      return (
        <Suspense fallback={<Spinner />}>
          <Routes>
            <Route path="/products/:id" element={<ProductDetails />} />
          </Routes>
        </Suspense>
      );
    }
    
  2. 상태 관리 전략: - 전역 상태와 지역 상태 구분 - 도메인별 상태 분리 - 서버 상태와 클라이언트 상태 분리

  3. 컴포넌트 설계 원칙: - 단일 책임 원칙 적용 - 컴포넌트 크기 제한 - 재사용 가능한 컴포넌트 라이브러리 구축

  4. 모듈화 및 경계 설정: - 명확한 API 경계 정의 - 내부 구현 세부 사항 캡슐화

  5. 문서화 및 스타일 가이드: - Storybook으로 컴포넌트 문서화 - 일관된 코딩 스타일 적용 (ESLint, Prettier)

  6. React 프로젝트에서 성능 최적화를 위한 실용적인 팁은 무엇인가요?

    React 성능 최적화 팁:

  7. 렌더링 최적화: - 컴포넌트 분할로 리렌더링 범위 제한 - React.memo, useMemo, useCallback 적절히 사용 - 상태 업데이트 일괄 처리

  8. 번들 크기 최적화: - 코드 분할 및 지연 로딩 - 트리 쉐이킹이 가능한 import 사용 - 번들 분석기로 큰 의존성 식별 - 불필요한 라이브러리 제거

  9. 이미지 및 미디어 최적화: - 적절한 이미지 포맷 사용 (WebP 등) - 이미지 크기 조정 및 압축 - 지연 로딩 적용

  10. 목록 렌더링 최적화: - 가상화 기술 사용 (react-window, react-virtualized) - 안정적인 키 사용 - 페이지네이션 또는 무한 스크롤 구현

  11. 네트워크 요청 최적화: - 데이터 프리페칭 - 캐싱 전략 구현 - GraphQL 사용 고려 (필요한 데이터만 요청)

  12. 메모리 관리: - 이벤트 리스너 정리 - 큰 객체 참조 해제 - 메모리 누수 모니터링

  13. 측정 및 모니터링: - Lighthouse, WebPageTest 등으로 정기적 성능 측정 - 사용자 중심 성능 지표 모니터링 (Core Web Vitals) - 실제 사용자 모니터링(RUM) 구현

  14. React 프로젝트에서 상태 관리 라이브러리를 선택하는 기준은 무엇인가요?

    상태 관리 라이브러리 선택 기준:

  15. 프로젝트 규모와 복잡성: - 작은 프로젝트: useState, useReducer, Context API - 중간 규모: Zustand, Jotai, Recoil - 대규모/복잡한 프로젝트: Redux Toolkit, MobX

  16. 팀 경험과 학습 곡선: - 팀의 기존 지식과 경험 - 문서화 품질과 커뮤니티 지원 - 학습 비용 대비 이점

  17. 성능 요구 사항: - 상태 업데이트 빈도 - 리렌더링 최적화 기능 - 메모리 사용량

  18. 기능 요구 사항: - 시간 여행 디버깅 필요성 - 미들웨어 지원 (비동기 작업, 로깅 등) - 상태 지속성 및 재수화 - 타입스크립트 지원

  19. 생태계와 지속 가능성: - 라이브러리 유지 관리 상태 - 업데이트 빈도 - 커뮤니티 크기와 활동성

  20. 통합 용이성: - 기존 코드베이스와의 통합 - 다른 라이브러리와의 호환성 - 점진적 도입 가능성

  21. React 프로젝트에서 효과적인 에러 처리 전략은 무엇인가요?

    React 에러 처리 전략:

  22. 에러 경계(Error Boundaries) 사용:
    class ErrorBoundary extends React.Component {
      state = { hasError: false, error: null };
           
      static getDerivedStateFromError(error) {
        return { hasError: true, error };
      }
           
      componentDidCatch(error, info) {
        console.error('Error caught:', error, info);
        // 에러 로깅 서비스에 보고
      }
           
      render() {
        if (this.state.hasError) {
          return <ErrorFallback error={this.state.error} />;
        }
        return this.props.children;
      }
    }
         
    // 사용
    <ErrorBoundary>
      <MyComponent />
    </ErrorBoundary>
    
  23. 비동기 에러 처리:
    const fetchData = async () => {
      try {
        setLoading(true);
        setError(null);
        const data = await api.fetchSomething();
        setData(data);
      } catch (error) {
        setError(error);
        // 에러 로깅
      } finally {
        setLoading(false);
      }
    };
    
  24. 전역 에러 핸들러:
    window.addEventListener('error', (event) => {
      // 전역 에러 처리
      console.error('Global error:', event.error);
      // 에러 로깅 서비스에 보고
    });
         
    window.addEventListener('unhandledrejection', (event) => {
      // 처리되지 않은 Promise 거부 처리
      console.error('Unhandled promise rejection:', event.reason);
      // 에러 로깅 서비스에 보고
    });
    
  25. 에러 로깅 및 모니터링: - Sentry, LogRocket 등의 서비스 활용 - 사용자 컨텍스트 정보 포함 - 에러 그룹화 및 우선순위 지정

  26. 사용자 친화적인 에러 UI: - 명확한 에러 메시지 제공 - 복구 옵션 제시 (재시도, 새로고침 등) - 기술적 세부 사항 숨기기

  27. 유효성 검사: - 입력 데이터 사전 검증 - 타입스크립트로 타입 안전성 확보 - 불변 조건 확인

  28. React 프로젝트에서 코드 품질을 유지하는 방법은 무엇인가요?

    React 코드 품질 유지 방법:

  29. 코드 표준화 도구: - ESLint: 코드 품질 및 스타일 규칙 적용 - Prettier: 일관된 코드 포맷팅 - TypeScript: 타입 안전성 확보

  30. 테스트 전략: - 단위 테스트: 개별 컴포넌트 및 함수 - 통합 테스트: 컴포넌트 간 상호작용 - E2E 테스트: 사용자 흐름 - 테스트 커버리지 모니터링

  31. 코드 리뷰 프로세스: - 명확한 리뷰 체크리스트 - 자동화된 코드 품질 검사 - 지식 공유 및 멘토링 기회로 활용

  32. 문서화: - Storybook으로 컴포넌트 문서화 - JSDoc 주석 활용 - README 및 개발 가이드 유지

  33. 지속적 통합/배포(CI/CD): - 자동화된 테스트 실행 - 린트 및 타입 검사 자동화 - 배포 전 품질 게이트 설정

  34. 코드 구조 및 설계: - 단일 책임 원칙 적용 - 컴포넌트 크기 제한 - 일관된 네이밍 컨벤션 - 중복 코드 최소화

  35. 성능 모니터링: - 정기적인 성능 감사 - 번들 크기 모니터링 - 메모리 누수 검사

  36. React Native와 React의 주요 차이점은 무엇인가요?

    React Native와 React 차이점:

  37. 렌더링 대상: - React: 웹 브라우저의 DOM에 렌더링 - React Native: 네이티브 모바일 컴포넌트로 렌더링

  38. 컴포넌트: - React: div, span, p 등 HTML 요소 사용 - React Native: View, Text, Image 등 플랫폼 중립적 컴포넌트 사용

  39. 스타일링: - React: CSS, CSS-in-JS, CSS Modules 등 사용 - React Native: JavaScript 객체 기반 스타일링, Flexbox 레이아웃

  40. 이벤트 처리: - React: onClick, onChange 등 DOM 이벤트 - React Native: onPress, onChangeText 등 플랫폼 특화 이벤트

  41. 애니메이션: - React: CSS 트랜지션, Web Animations API 등 - React Native: Animated API, LayoutAnimation 등

  42. 네이티브 기능 접근: - React: 웹 API를 통해 제한된 기능 접근 - React Native: 네이티브 모듈을 통해 기기 기능 직접 접근

  43. 개발 환경: - React: 웹 브라우저에서 개발 및 디버깅 - React Native: 시뮬레이터/에뮬레이터 또는 실제 기기에서 개발

  44. 배포:
    • React: 웹 서버에 배포
    • React Native: 앱 스토어를 통해 배포, OTA 업데이트 가능
  45. 성능:
    • React: 브라우저 성능에 의존
    • React Native: 네이티브 스레드와 JS 스레드 간 통신으로 인한 오버헤드 존재
  46. 학습 곡선:
    • React: 웹 개발 지식만 필요
    • React Native: 모바일 개발 개념과 플랫폼별 특성 이해 필요
  47. React 프로젝트에서 국제화(i18n)를 구현하는 방법은 무엇인가요?

    React 국제화(i18n) 구현 방법:

  48. 라이브러리 선택: - react-intl: 포맷팅 기능이 강력 - i18next: 유연하고 확장성 높음 - react-i18next: i18next의 React 바인딩

  49. 기본 설정 (react-i18next 예시):
    // i18n.js
    import i18n from 'i18next';
    import { initReactI18next } from 'react-i18next';
         
    i18n
      .use(initReactI18next)
      .init({
        resources: {
          en: {
            translation: {
              welcome: 'Welcome to our app',
              greeting: 'Hello, !'
            }
          },
          ko: {
            translation: {
              welcome: '앱에 오신 것을 환영합니다',
              greeting: '안녕하세요, 님!'
            }
          }
        },
        lng: 'en',
        fallbackLng: 'en',
        interpolation: {
          escapeValue: false
        }
      });
         
    export default i18n;
    
  50. 번역 사용:
    import { useTranslation } from 'react-i18next';
         
    function Welcome({ name }) {
      const { t } = useTranslation();
           
      return (
        <div>
          <h1>{t('welcome')}</h1>
          <p>{t('greeting', { name })}</p>
        </div>
      );
    }
    
  51. 언어 전환:
    function LanguageSwitcher() {
      const { i18n } = useTranslation();
           
      return (
        <div>
          <button onClick={() => i18n.changeLanguage('en')}>English</button>
          <button onClick={() => i18n.changeLanguage('ko')}>한국어</button>
        </div>
      );
    }
    
  52. 복수형, 날짜, 숫자 포맷팅:
    // 복수형
    t('items', { count: 5 }); // "5 items" 또는 "5개 항목"
         
    // 날짜 포맷팅
    t('date', { date: new Date(), formatParams: { date: { month: 'long' } } });
         
    // 숫자 포맷팅
    t('price', { price: 1000.5, formatParams: { price: { style: 'currency', currency: 'USD' } } });
    
  53. 번역 파일 관리: - 언어별 JSON 파일 분리 - 네임스페이스로 도메인별 번역 구성 - 동적 로딩으로 필요한 번역만 로드

  54. React 프로젝트에서 접근성(a11y)을 구현하는 실용적인 방법은 무엇인가요?

    React 접근성 구현 방법:

  55. 기본 접근성 원칙 적용: - 시맨틱 HTML 요소 사용 - 적절한 ARIA 속성 추가 - 키보드 탐색 지원 - 충분한 색상 대비 제공

  56. 접근성 도구 활용: - ESLint의 jsx-a11y 플러그인:
     npm install eslint-plugin-jsx-a11y --save-dev
    
    - Lighthouse, axe 등의 접근성 감사 도구
    - 스크린 리더 테스트 (VoiceOver, NVDA, JAWS)
    
  57. 폼 접근성:
    <div>
      <label htmlFor="name">Name:</label>
      <input
        id="name"
        type="text"
        aria-describedby="name-error"
        aria-invalid={!!errors.name}
      />
      {errors.name && (
        <div id="name-error" className="error">
          {errors.name}
        </div>
      )}
    </div>
    
  58. 동적 콘텐츠 알림:
    function Notifications() {
      const [messages, setMessages] = useState([]);
           
      return (
        <div>
          <ul>
            {messages.map(msg => (
              <li key={msg.id}>{msg.text}</li>
            ))}
          </ul>
          {/* 새 메시지가 추가될 때 스크린 리더에 알림 */}
          <div aria-live="polite" className="sr-only">
            {messages.length > 0 && `New message: ${messages[0].text}`}
          </div>
        </div>
      );
    }
    
  59. 포커스 관리:
    function Modal({ isOpen, onClose, children }) {
      const modalRef = useRef();
           
      useEffect(() => {
        if (isOpen) {
          // 모달 열릴 때 포커스 이동
          modalRef.current?.focus();
               
          // 포커스 트랩 구현
          const handleKeyDown = (e) => {
            if (e.key === 'Escape') {
              onClose();
            }
            // 탭 키 처리로 포커스가 모달 내에 머물도록 함
          };
               
          document.addEventListener('keydown', handleKeyDown);
          return () => {
            document.removeEventListener('keydown', handleKeyDown);
          };
        }
      }, [isOpen, onClose]);
           
      if (!isOpen) return null;
           
      return (
        <div
          ref={modalRef}
          role="dialog"
          aria-modal="true"
          aria-labelledby="modal-title"
          tabIndex={-1}
        >
          <h2 id="modal-title">Modal Title</h2>
          {children}
          <button onClick={onClose}>Close</button>
        </div>
      );
    }
    
  60. 접근성 테스트 자동화: - Jest와 Testing Library로 접근성 테스트 - CI/CD 파이프라인에 접근성 검사 통합

  61. React 프로젝트에서 보안 모범 사례는 무엇인가요?

    React 보안 모범 사례:

  62. XSS(Cross-Site Scripting) 방지: - React의 자동 이스케이프 활용 (기본적으로 제공) - 위험한 props 사용 주의:
     // 위험: 사용자 입력을 직접 HTML로 삽입
     <div dangerouslySetInnerHTML= />
          
     // 대안: 텍스트로 렌더링
     <div>{userInput}</div>
    
    - 신뢰할 수 없는 URL 검증:  ```jsx  // URL 검증 함수  const isSafeURL = (url) => {    try {
     const parsed = new URL(url);
     return ['https:', 'http:'].includes(parsed.protocol);    } catch {
     return false;    }  };
    

    // 사용 <a href={isSafeURL(userProvidedURL) ? userProvidedURL : ‘#’}>Link</a> ```

  63. 민감한 데이터 관리: - 환경 변수로 API 키 관리 (.env 파일) - 클라이언트 측 코드에 민감한 정보 포함 금지 - localStorage/sessionStorage에 민감한 데이터 저장 주의

  64. 의존성 보안: - 정기적인 의존성 업데이트 - npm audit 또는 Snyk 등으로 취약점 검사 - package-lock.json 또는 yarn.lock 파일 버전 관리

  65. API 요청 보안: - CSRF 토큰 사용 - 적절한 인증 헤더 설정 - 요청 및 응답 데이터 검증

  66. 인증 및 권한 관리: - JWT 토큰 안전하게 저장 (httpOnly 쿠키 선호) - 토큰 만료 처리 - 권한 기반 UI 렌더링

  67. CSP(Content Security Policy) 설정: - 인라인 스크립트 제한 - 신뢰할 수 있는 소스만 허용

  68. 사용자 입력 검증: - 클라이언트 측과 서버 측 모두에서 검증 - 입력 데이터 정규화 및 필터링

  69. React 프로젝트에서 CI/CD 파이프라인을 구성하는 방법은 무엇인가요?

    React CI/CD 파이프라인 구성:

  70. CI/CD 도구 선택: - GitHub Actions, GitLab CI, CircleCI, Jenkins 등

  71. 기본 CI 파이프라인 구성 (GitHub Actions 예시):
    # .github/workflows/ci.yml
    name: CI
         
    on:
      push:
        branches: [ main, develop ]
      pull_request:
        branches: [ main, develop ]
         
    jobs:
      build-and-test:
        runs-on: ubuntu-latest
             
        steps:
        - uses: actions/checkout@v3
             
        - name: Set up Node.js
          uses: actions/setup-node@v3
          with:
            node-version: '16'
            cache: 'npm'
             
        - name: Install dependencies
          run: npm ci
             
        - name: Lint
          run: npm run lint
             
        - name: Type check
          run: npm run typecheck
             
        - name: Run tests
          run: npm test -- --coverage
             
        - name: Build
          run: npm run build
             
        - name: Upload build artifacts
          uses: actions/upload-artifact@v3
          with:
            name: build
            path: build/
    
  72. CD 파이프라인 추가:
    # .github/workflows/cd.yml
    name: CD
         
    on:
      push:
        branches: [ main ]
         
    jobs:
      deploy:
        runs-on: ubuntu-latest
        needs: build-and-test
             
        steps:
        - name: Download build artifacts
          uses: actions/download-artifact@v3
          with:
            name: build
            path: build
             
        - name: Deploy to production
          uses: some-deploy-action@v1
          with:
            api-key: $
            app-name: my-react-app
            deploy-path: build/
    
  73. 환경별 배포 구성: - 개발(dev), 스테이징(staging), 프로덕션(prod) 환경 설정 - 환경별 환경 변수 및 구성 관리 - 브랜치 기반 배포 전략 (GitFlow 등)

  74. 품질 게이트 추가: - 테스트 커버리지 임계값 설정 - 성능 및 접근성 검사 - 보안 취약점 스캔

  75. 배포 자동화: - AWS S3 + CloudFront - Netlify, Vercel 등의 정적 호스팅 서비스 - Docker 컨테이너화 및 Kubernetes 배포

  76. React 프로젝트에서 기술 부채를 관리하는 방법은 무엇인가요?

    React 기술 부채 관리 방법:

  77. 기술 부채 식별: - 정기적인 코드 품질 검토 - 정적 분석 도구 활용 (SonarQube 등) - 성능 및 유지보수성 지표 모니터링

  78. 점진적 리팩토링: - 보이 스카우트 규칙 적용 (코드를 발견했을 때보다 더 깨끗하게 남기기) - 새 기능 개발과 함께 관련 코드 개선 - 리팩토링을 위한 전용 시간 할당

  79. 레거시 코드 현대화: - 클래스 컴포넌트를 함수형 컴포넌트로 마이그레이션 - 오래된 패턴 및 라이브러리 업데이트 - 타입스크립트 점진적 도입

  80. 문서화 개선: - 코드 주석 및 JSDoc 추가 - 아키텍처 결정 기록(ADR) 유지 - 기술 부채 항목 문서화 및 우선순위 지정

  81. 테스트 커버리지 향상: - 레거시 코드에 대한 테스트 추가 - 회귀 테스트 자동화 - 테스트 가능한 코드 설계 촉진

  82. 의존성 관리:
    • 정기적인 의존성 업데이트
    • 사용하지 않는 의존성 제거
    • 의존성 버전 고정 및 호환성 확인
  83. 코드 복잡성 감소:
    • 큰 컴포넌트 분할
    • 복잡한 로직 추상화
    • 중복 코드 제거
  84. 성능 최적화:
    • 렌더링 병목 현상 식별 및 해결
    • 번들 크기 최적화
    • 메모리 누수 수정
  85. React 프로젝트에서 디자인 시스템을 구축하고 유지하는 방법은 무엇인가요?

    React 디자인 시스템 구축 및 유지:

  86. 디자인 토큰 정의:
    // theme.js
    export const theme = {
      colors: {
        primary: '#0070f3',
        secondary: '#ff4081',
        text: {
          primary: '#333333',
          secondary: '#666666',
        },
        background: {
          default: '#ffffff',
          paper: '#f5f5f5',
        }
      },
      spacing: {
        xs: '4px',
        sm: '8px',
        md: '16px',
        lg: '24px',
        xl: '32px',
      },
      typography: {
        fontFamily: "'Roboto', sans-serif",
        fontSize: {
          xs: '12px',
          sm: '14px',
          md: '16px',
          lg: '20px',
          xl: '24px',
        },
        fontWeight: {
          regular: 400,
          medium: 500,
          bold: 700,
        }
      },
      breakpoints: {
        xs: '0px',
        sm: '600px',
        md: '960px',
        lg: '1280px',
        xl: '1920px',
      }
    };
    
  87. 기본 컴포넌트 구축:
    // Button.jsx
    import styled from 'styled-components';
    import { theme } from '../theme';
         
    const StyledButton = styled.button`
      background-color: ${props => props.variant === 'primary' 
        ? theme.colors.primary 
        : 'transparent'};
      color: ${props => props.variant === 'primary' 
        ? '#fff' 
        : theme.colors.primary};
      border: ${props => props.variant === 'primary' 
        ? 'none' 
        : `1px solid ${theme.colors.primary}`};
      padding: ${theme.spacing.sm} ${theme.spacing.md};
      border-radius: 4px;
      font-family: ${theme.typography.fontFamily};
      font-size: ${theme.typography.fontSize.md};
      font-weight: ${theme.typography.fontWeight.medium};
      cursor: pointer;
           
      &:hover {
        opacity: 0.9;
      }
           
      &:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }
    `;
         
    export const Button = ({ children, variant = 'primary', ...props }) => {
      return (
        <StyledButton variant={variant} {...props}>
          {children}
        </StyledButton>
      );
    };
    
  88. 컴포넌트 문서화 (Storybook):
    // Button.stories.jsx
    import { Button } from './Button';
         
    export default {
      title: 'Components/Button',
      component: Button,
      argTypes: {
        variant: {
          control: { type: 'select', options: ['primary', 'secondary', 'outline'] },
          defaultValue: 'primary',
        },
        disabled: {
          control: 'boolean',
          defaultValue: false,
        },
      },
    };
         
    const Template = (args) => <Button {...args} />;
         
    export const Primary = Template.bind({});
    Primary.args = {
      children: 'Primary Button',
      variant: 'primary',
    };
         
    export const Secondary = Template.bind({});
    Secondary.args = {
      children: 'Secondary Button',
      variant: 'secondary',
    };
         
    export const Disabled = Template.bind({});
    Disabled.args = {
      children: 'Disabled Button',
      disabled: true,
    };
    
  89. 컴포넌트 라이브러리 구성: - 모노레포 설정 (Nx, Lerna, Turborepo 등) - 컴포넌트 패키지화 및 버전 관리 - npm/yarn에 배포 또는 비공개 레지스트리 사용

  90. 디자인 시스템 가이드라인: - 사용 패턴 및 모범 사례 문서화 - 접근성 지침 포함 - 컴포넌트 조합 예시 제공

  91. 테마 및 스타일링 전략: - CSS-in-JS (styled-components, emotion) - 테마 제공자 구현 - 다크 모드 지원

  92. 디자인-개발 협업: - Figma와 같은 디자인 도구와 통합 - 디자인 토큰 동기화 - 디자이너와 개발자 간 공통 언어 구축

  93. React 프로젝트에서 확장 가능한 상태 관리 아키텍처를 설계하는 방법은 무엇인가요?

    확장 가능한 상태 관리 아키텍처:

  94. 상태 계층화: - 로컬 상태: 단일 컴포넌트 내에서만 사용되는 UI 상태 - 공유 상태: 여러 컴포넌트에서 사용되는 상태 - 서버 상태: API에서 가져온 데이터 - 전역 상태: 앱 전체에서 사용되는 상태

  95. 도메인 중심 상태 분리:
    // Redux 예시
    // store/auth/slice.js
    import { createSlice } from '@reduxjs/toolkit';
         
    const authSlice = createSlice({
      name: 'auth',
      initialState: {
        user: null,
        isAuthenticated: false,
        loading: false,
        error: null
      },
      reducers: {
        // 리듀서 정의
      }
    });
         
    // store/products/slice.js
    const productsSlice = createSlice({
      name: 'products',
      initialState: {
        items: [],
        loading: false,
        error: null
      },
      reducers: {
        // 리듀서 정의
      }
    });
    
  96. 상태 접근 추상화:
    // hooks/useAuth.js
    export function useAuth() {
      const user = useSelector(state => state.auth.user);
      const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
      const loading = useSelector(state => state.auth.loading);
      const error = useSelector(state => state.auth.error);
      const dispatch = useDispatch();
           
      const login = useCallback((credentials) => {
        dispatch(authActions.loginRequest(credentials));
      }, [dispatch]);
           
      const logout = useCallback(() => {
        dispatch(authActions.logout());
      }, [dispatch]);
           
      return {
        user,
        isAuthenticated,
        loading,
        error,
        login,
        logout
      };
    }
    
  97. 서버 상태와 클라이언트 상태 분리:
    // 서버 상태 관리 (React Query)
    function ProductList() {
      const { data: products, isLoading, error } = useQuery(
        'products',
        fetchProducts
      );
           
      // UI 렌더링
    }
         
    // 클라이언트 상태 관리 (useState/Redux)
    function ShoppingCart() {
      const { items, addItem, removeItem } = useCart();
           
      // UI 렌더링
    }
    
  98. 비동기 작업 처리:
    // Redux Toolkit 예시
    const fetchUserProfile = createAsyncThunk(
      'users/fetchUserProfile',
      async (userId, { rejectWithValue }) => {
        try {
          const response = await api.get(`/users/${userId}`);
          return response.data;
        } catch (error) {
          return rejectWithValue(error.response.data);
        }
      }
    );
         
    // React Query 예시
    const { data, isLoading, error } = useQuery(
      ['user', userId],
      () => fetchUserProfile(userId),
      {
        staleTime: 5 * 60 * 1000, // 5분
        retry: 3,
        onError: (error) => {
          // 에러 처리
        }
      }
    );
    
  99. 상태 지속성 및 동기화:
    // Redux Persist 예시
    import { persistStore, persistReducer } from 'redux-persist';
    import storage from 'redux-persist/lib/storage';
         
    const persistConfig = {
      key: 'root',
      storage,
      whitelist: ['auth', 'cart'] // 유지할 상태 지정
    };
         
    const persistedReducer = persistReducer(persistConfig, rootReducer);
         
    export const store = configureStore({
      reducer: persistedReducer,
      // 기타 설정
    });
         
    export const persistor = persistStore(store);
    
  100. 성능 최적화: - 선택적 상태 구독 - 정규화된 상태 구조 - 메모이제이션 활용

  101. React 프로젝트에서 지속적인 학습과 개선을 촉진하는 방법은 무엇인가요?

    지속적인 학습과 개선 방법:

  102. 코드 리뷰 문화 구축: - 건설적인 피드백 장려 - 지식 공유 기회로 활용 - 코드 품질 및 일관성 향상

  103. 기술 공유 세션: - 정기적인 팀 내 기술 발표 - 새로운 라이브러리나 패턴 소개 - 프로젝트 문제 해결 사례 공유

  104. 실험 및 프로토타이핑: - 새로운 기술 탐색을 위한 시간 할당 - 프로토타입 개발 및 평가 - 성공적인 실험 결과 통합

  105. 회고 및 개선 사이클: - 정기적인 팀 회고 진행 - 개선 항목 식별 및 우선순위 지정 - 점진적 개선 계획 수립

  106. 학습 리소스 공유: - 유용한 블로그, 문서, 강의 공유 - 내부 지식 베이스 구축 - 학습 커뮤니티 참여 장려

  107. 성능 및 사용자 경험 측정: - 핵심 성능 지표 모니터링 - 사용자 피드백 수집 및 분석 - 데이터 기반 개선 결정

  108. 외부 커뮤니티 참여: - 오픈 소스 기여 - 기술 컨퍼런스 참석 - 블로그 작성 및 지식 공유

이 면접 질문 모음은 React의 기초부터 고급 개념까지 다양한 주제를 다루고 있습니다. 각 질문에 대한 답변은 실무 경험과 최신 React 동향을 반영하고 있으며, 면접 준비뿐만 아니라 React 개발자로서의 지식을 넓히는 데도 도움이 될 것입니다.

Categories:

Updated:

Leave a comment