React 면접 준비

홍범선·2024년 12월 23일
0

면접

목록 보기
1/1

브라우저 렌더링 과정에 대해서 설명해보세요

  1. HTML을 브라우저가 전달받으면 브라우저 렌더 엔진이 이를 파싱한다.
  2. Dom Node로 이루어진 tree를 생성한다.
  3. CSS파일과 inline 스타일을 파싱한다.
  4. 스타일을 추가한 렌더트리를 생성한다.
  5. 그 후 레이아웃 과정을 거친다.
    • 각 노드들은 스크린의 좌표가 주어진다.
  6. 페인팅 과정을 거친다.
  7. 이제 화면에 보이게 된다.

DOM을 조작할 때마다 이런 과정이 반복되는 것은 비용이 많이 든다.

이 문제를 해결하기 위해서 virtual DOM이 등장한다.

virtual DOM이란

  • DOM 노드 트리를 복제한 자바스크립트 객체이다.
  • 가벼운 버전이다.
    • class, style 등은 가지고 있다.
    • getElementbyId와 같은 DOM API는 가지고 있지 않다.
  • virtual DOM은 실제로 렌더링하지 않고 메모리 상 트리를 변경한다.
  • 이전 DOM Tree와 이후 DOM Tree를 비교해 변경된 부분만 확인한다.
  • 실제 DOM에 변경된 부분만 재 렌더링한다.

브라우저 렌더링을 과정을 계속해서 반복하는 것이 아니라 변화들을 virtual DOM에 반영한 후, 변화된 부분만을 모아서 실제 DOM에 적용하여 한 번만 렌더링 하도록 함으로써 성능을 최적화 합니다.

React의 Virtual Dom

  • jsx 문법을 Babel이 자바스크립트로 변환한다.
  • 컴포넌트를 createElement등으로 자바스크립트 객체로 변환한다.
  • 객체에는 type = 태그이름, props = 하위노드, 각종 속성 포함이 담겨있다.
  • 이러한 객체를 활용하여 virtual DOM 트리를 형성한다.
  • 이러한 객체를 활용하여 render()함수를 호출하면 실제 DOM요소가 된다.

리액트는 virtual Dom 이전과, virtual Dom 이후를 가지고 있다.
이 두 트리의 스냅샷을 비교하여 변화된 부분만을 감지한 후에 변경된 부분만을 실제 DOM에 적용한다.

React의 Diff 알고리즘

babel에 의해 변환된 자바스크립트에는 type, props가 존재한다.
만약 type === type일 때 props의 속성들을 비교해 변환된 속성만 업데이트 시켜준다.
만약 type !== type일 때 리액트는 이전 트리를 삭제하고 완전히 새로운 트리를 생성한다.

React에서 key Props를 주는 이유

리액트에서 재조정과정에서 이전 virtual Dom과 새로운 virtual Dom을 비교한다.
자식 노드가 추가되었을 때 key값을 통해서 변경여부를 확인하는데 이 때 유니크한 값이 아닌 index로 하게 되면 제대로 동작하지 않을 수 있다.

바벨이란?

ES5+ 코드를 자바스크립의 하위 호환 버전으로 변환하여 오래된 브라우저에서 실행하도록 변환하는 컴파일러입니다. 더 나아가 JSX까지 변환해준다.

리랜더링 되는 조건은 무엇인가요?

  • state가 바뀌었을 때
  • props가 바뀌었을 때

props로 함수를 넘겨주었을 때 어떤 일이 일어나나요?

부모 컴포넌트가 리렌더링 될 때마다 함수는 재생성이 되고 이전 함수와, 현재 함수가 서로 다른 참조 타입을 가지기 때문에 조치를 취하지 않는 이상 랜더링이 발생한다.
이 때 리액트에서 제공하는 useCallback hook을 사용하면 함수를 메모리제이션 해준다.

useCallback을 해도 리랜더링이 발생하는데 렌더링 최적화에 아무런 효과가 없나요?

리액트 렌더링은 render phasecommit phase로 구성되어 있습니다.
render phase에는 컴포넌트를 호출하여 React.Element를 반환하고 새로운 virtual Dom을 생성해줍니다. 그 후 재조정 과정을 거친 후 변경사항을 체크합니다.
commit phase는 변경 사항을 real Dom에 반영합니다.
=> 즉 render phase는 실행되지만 usecallback을 활용해서 props 값을 이전과 같게 유지해주었기 때문에 commit phase는 실행되지 않습니다.

render Phase도 막아줄 방법은 없을까요?

React.Memo를 사용하면 됩니다.
React.Memo란 전달받은 props가 이전 props와 비교했을 때 같으면, 컴포넌트의 리랜더링을 막아주고, 마지막으로 렌더링 된 결과를 재사용하는 고차 컴포넌트입니다.
=> 즉 컴포넌트가 render phase에 진입하기 전 props의 이전 값과 현재 값을 비교를 하는데요. 같으면 랜더링이 진행되지 않고 이전 렌더링 결과를 리턴하게 됩니다.

props로 객체를 넘겨주었을 때 어떤 일이 일어나나요?

함수와 마찬가지로 객체는 참조 타입이기 때문에 렌더링 될 때마다 매번 다른 참조값을 가진 props를 전달하게 됩니다. 그래서 자식 컴포넌트들도 렌더링 되게 됩니다.
이 때 useMemo hook을 사용하면 값에 대한 메모리제이션을 할 수 있습니다.

useCallback, useMemo, React.memo를 모든 곳에 사용해주는 곳이 좋을까요?

이러한 것들도 코드이고 내부적으로 로직들이 실행이 되기 비용이 생깁니다. 매번 바뀔 수 밖에 없는 props에 useMemo를 쓰던가, 매번 렌더링이 되는 컴포넌트에 useCallback을 하게 되면 오히려 성능이 저하될 수 있습니다.
=> 따라서 컴포넌트를 props로 주입하는 코드를 작성하게 된다면 됩니다.

useState와 useReducer를 선택하는 기준에 대해서 설명하세요

useState는 true/false나 string 같은 단순한 상태값일 때 사용
useReducer는 입력 폼이라던지, 복잡한 상태관리를 reducer로 분리하면 서로 의존적인 상태들을 깔끔하게 관리할 수 있다.

리액트에서 커스텀 훅을 사용하는 이유와 장점은 무엇인가요?

use로 시작하는 사용자 정의 함수로 여러 컴포넌트에서 재사용 가능한 상태 로직을 말합니다. 함수처럼 재사용 가능한 비즈니스 로직을 분리하여 다른 컴포넌트에서 재사용할 수 있고, 재사용하지 않더라도 비즈니스 로직을 분리하여 코드 가독성을 향상할 수 있습니다.

useEffect에 장점과 단점은 무엇인가요?

useEffect는 의존성 배열이 있는데 의존성 배열 값이 변하면 사이드 이펙트로 실행해주는 훅입니다. 또한 컴포넌트가 언마운트 될 때 리소스를 정리할 경우 사용합니다.
단점으로는 의존성 배열을 제대로 사용하지 않으면 불필요한 렌더링이 발생할 수 있습니다.

코드 스플리팅이 무엇인가요?

리액트와 같은 SPA로 개발된 프로젝트는 빌드를 통해 배포됩니다.
빌드된 결과물을 보면, 하나의 큰 JavaScript 파일로 모든 코드가 번들링된 것을 확인할 수 있습니다.
이 경우, 초기 로딩 시 모든 페이지의 코드가 한 번에 불러와지므로, 첫 번째 로딩 시간이 길어지는 문제가 발생할 수 있습니다.
이를 해결하기 위해, 필요한 부분만 동적으로 로드하는 기술을 활용하여 성능을 최적화할 수 있습니다.

코드 스플리팅을 구현하려면 어떻게 해야하나요?

React.lazy와, suspense를 사용하면 됩니다.
React.lazy는 동적으로 불러올 컴포넌트를 import하면 되고
React.suspense에서 React.lazy가 적용된 컴포넌트를 렌더링하면 됩니다.

리액트에서 useContext를 사용하여 상태를 공유할 때 장점과 주의 사항을 설명해 주세요

Context API를 사용하게 되면 props 깊이가 깊어지는 props drilling 문제를 해결할 수 있습니다.

profile
알고리즘 정리 블로그입니다.

0개의 댓글