개발/프론트엔드 Job Interview

리액트 기본 개념 QnA. 2탄 (feat. 면접 뽀개기)

차얀 2021. 12. 18. 17:04

children prop이란 무엇인가요?

커스텀 컴포넌트 태그 사이에 삽입되는 태그들을 

해당 커스텀 컴포넌트 태그에서 children이라는 prop으로 받아서 사용할 수 있습니다.

만약 이를 타입스크립트와 같이 사용한다면 React.ReactNode 라는 타입으로 선언해 사용하면 됩니다.

function App() {
	return (
    	<CustomTag>
        	<h1>This is Title</h1>
            <p>Hello World!</p>
        </CustomTag>
    )
}

// ===

function CustomTag({children}) { // children에서 위 기준 h1, p 태그를 담고 있습니다.
 return (...)
}

 

 

 

클래스 컴포넌트의 super constructor가 존재하는 이유가 무엇일까요?

super는 부모 클래스 생성자를 참조한다는 것을 의미하기에
자바스크립트 레벨에서 super를 호출하기 전에는 this를 사용할 수가 없습니다.

 

class App extends React.Component {
	constructor(props) {
		// 여기서는 this를 사용할 수 없다
		super(props);
		// 이제 this 사용 가능!
		this.state = { count : 0 }
	...

 

만약 super보다 this를 먼저 사용한다고 가정해보겠습니다.

super를 이용해 상위 클래스의 this 내용을 호출하기도 전에,
현재 extend 한 클래스의 메서드에서 상위 클래스의 this를 호출한다면 상황이 애매해집니다.

이런 경우를 방지하기 위해 자바스크립트 자체에서 this 사용전에 super 호출을 강제해,

미리 상위 클래스의 this를 선언해줍니다. 

 

class Person {
  constructor(name) {
    this.name = name;
  }
}

class CompanyPerson extends Person {
  constructor(name) {
    this.greeting();  // super 보다 내부 메서드 먼저 호출하는 상황
    super(name);
  }
  greeting() {
    alert('My name is ' + this.name);  // this.name의 초기화 여부가 확실하지 않다...
  }
}

 

 

createElement와 cloneElement의 차이점은 무엇일까요?

둘은 서로 목적성이 다릅니다.

 

createElement는 리액트에서 주어진 속성들을 이용해 DOM을 생성하는 메서드입니다.

즉, 사용자 UI가 어떻게 생겼는지 명시하는 역할을 수행합니다.

type, props, children에 대한 정보를 요구합니다.

이는 JSX(createElement의 문법 슈가)로 인해 자동화 되어있어, 직접적으로 createElement를 사용할 일은 적습니다.

 

cloneElement는 주어진 DOM 엘리먼트를 클론하는데 사용됩니다.

즉, DOM 엘리먼트를 복제하는데 사용됩니다.

elements, props, children에 대한 정보를 요구합니다.

부모 컴포넌트가 자식 컴포넌트들에 대한 props를 추가하거나 변경하고 싶을때 사용되는 방법입니다.

 

 

 

ref란 무엇이고 이를 사용하는 이유는 무엇인가요?

간단하게 말하면, 리액트에서 DOM에 이름을 다는 방법이 바로 ref 입니다.

리액트에서 state와 같은 방법으로 해결할 수 없고, DOM을 직접적으로 건드려야 하는 경우가 있습니다.

공식 문서에서는

 

1. 포커스, 텍스트 선택, 미디어 재생 관리

2. 애니메이션 직접 실행

3. 서드 파티 DOM 라이브러리 같이 사용할때

 

와 같은 경우를 ref를 사용하는 바람직한 사례로 규명되어 있습니다.

 

그리고 굳이 ref를 사용하지 않고도 해결할 수 있는 상황에 대해선, ref를 지양하기를 권장합니다.

이런 ref는 forwardRef 방식을 이용해 다른 컴포넌트에서 이를 조작할 수 있게 되는데,

이는 캡슐화를 깨트려버리게 됩니다.

또, 상태 관리 측면에서도 ref를 남용하게 되면 상태에 대한 통제가 어려워지게 되기 때문입니다.

 

 

 

fowardRef가 무엇을 의미하는건가요?

부모 컴포넌트에서 자식 컴포넌트로 ref를 전달해서 부모가 자식 ref를 참조하는 기술을 의미합니다.

 

 

 

React fiber가 뭔가요?

Fiber는 리액트 v16에 나온 새로운 재조정 알고리즘입니다.

이 엔진의 목표는 애니메이션, 레이아웃, 제스쳐 분야에서 적합성을 높이는 것입니다.

 

리액트에선 재조정 알고리즘을 통해 DOM에 업데이트 있을때마다 다시 랜더링을 수행합니다.

이때, 전체 App 트리를 순회하고 다시 렌더링 되기까지 일정 시간 이상 걸리게 되면,
프레임이 삭제되어 문제가 발생하게 됩니다.

이로 인해 애니메이션 렌더링시 일부 과정이 생략되는것처럼 보이게 되는 문제가 발생하게 됩니다.

 

이를 위해 렌더링 과정을 여려 조각으로 나누었습니다.

그리고 이 조각들에게 우선순위를 부여했습니다.

이 방법이 바로 동시성을 의미하는 것이고, 이는 렌더링 과정이 JS 스레드(싱글 스레드)를 블록하지 않습니다.

즉, 콜스택과 문맥 교환(context switching) 개념을 구현해, 이런 문제를 해결했습니다.

개념보다 자세히 알아보기(영상)

 

 

 

리액트 동시성(concurrent) 모드가 뭔가요?

리액트에서 재조정 알고리즘을 시작하면 이를 멈출 수 없습니다.

즉, 이 과정이 끝날때까지 메인 UI 스레드(싱글 스레드)에선 사용자 입력을 받거나 하는 다른 작업을 수행할 수 없습니다.

결국 이는 프레임 저하나 화면의 끊김 현상으로 이어집니다.

 

이러한 문제를 해결하기 위해 쓰로틀링, 디바운싱같은 방법을 사용하긴 하지만 결국 근본적 문제를 해결하진 못합니다.

 

이를 위해 렌더링 과정을 여려 조각으로 나누었습니다.

그리고 이 조각들에게 우선순위를 부여했습니다.

이 방법이 바로 동시성을 의미하는 것이고, 이는 렌더링 과정이 JS 스레드(싱글 스레드)를 블록하지 않습니다.

그리고, 사용자 입력과 같은 우선순위 높은 작업이 실행되면 렌더링의 우선순위를 뒤로 미룰 수 있습니다.

(리액트 Fiber의 역할)

 

이런 점을 이용해 리액트에서 제공하는

 - Suspense : 프라미스로 감싸진 비동기 API 호출 기다리며 보여줄 화면 명시하는 컴포넌트

 - SuspenseList : 여러 Suspense에 대해 우선순위 설정

 - useDefferedValue

 - useTransition

과 같은 기능을 사용할 수 있게됩니다.

 

 

 

에러 바운더리란 무엇인가요?

특정 컴포넌트에서 발생하는 자바스크립트 오류가 전체앱을 망가트리는 대신,

에러 바운더리 컴포넌트를 통해 폴백 UI를 보여주는 방법입니다.

 

내부에서 getDrivedStateFromError, componentDidCatch를 이용해 에러 로그 기록 및 처리를 할 수 있습니다.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {    
    // 다음 렌더링에서 폴백 UI가 보이도록 상태를 업데이트 합니다.    
    return { hasError: true };  
  }
  
  componentDidCatch(error, errorInfo) {    
    // 에러 리포팅 서비스에 에러를 기록할 수도 있습니다.    
    logErrorToMyService(error, errorInfo);  
  }
  
  render() {
    if (this.state.hasError) {      
      // 폴백 UI를 커스텀하여 렌더링할 수 있습니다.      
      return <h1>Something went wrong.</h1>;    
    }
    
    return this.props.children;
  }
}
<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

 

 

 

React.lazy의 개념과 이를 사용하는 이유와 방법을 아는가?

주로 성능개선을 위해 사용하는 방법으로,

지금 당장 필요하지 않은 컴포넌트를 나중에 호출하는 방식으로 적용하는 방법입니다.

 

 

 

리액트에선 class 속성이 아닌 className 속성을 사용하는 이유는?

리액트에서 class는 예약어라 사용할 수 없습니다 

(자바스크립트에서 이미 class를 사용하고 있다는 뜻)

 



리액트 fragment란 무엇일까요?

리액트 컴포넌트에서 반환되는 JSX는 반드시 최상위 태그가 있어야 하는데,

이때 무의미한 최상위 태그를 사용하는 것을 방지하기 위한 방법입니다.

실제로 렌더링 될때, fragment 태그는 렌더링에 적용되지 않습니다.

 

 

 

React.portal의 개념과 이를 사용하는 이유는 무엇인가?

현재 기존 리액트 컴포넌트 관계에 DOM을 종속되지 않게끔 컴포넌트를 별도의 최상위 태그에 렌더링 하는 방법입니다.

ReactDOM.createPortal(child, container)

보통 모달이나 dnd 모듈과 같이 기존 컴포넌트 종속 관계와 독립적으로 작동 시키고 싶은 기능에서 사용되곤 합니다.

 

 

 

react와 reactDom의 차이점에 대해

리액트 자바스크립트 UI 라이브러리입니다.

reactDom은 리액트를 웹 사이트에 출력(render) 하는것을 도와주는 모델입니다,

만약 모바일 앱을 개발하면, reactDOM 대신 reactNative를 사용하게 됩니다.

 

 

 

reactDOMServer은 무엇인가요?

컴포넌트를 정적 마크업으로 렌더링할 수 있는 방법입니다.

보통 node 서버에서 사용되고, SSR을 구현하기 위해 사용됩니다.

 

 

 

리액트에서 innerHTML을 사용하는 방법은?

dangerouslySetInnerHTML 속성을 이용해 innerHTML을 리액트 에서 사용할 수 있습니다.

하지만, innerHTML를 코드상에서 설정하는것은 XXS(사이트 간 스크립팅) 공격에 쉽게 노출되기에 지양해야합니다.

 

 

 

dependency array에 배열이나 객체가 들어오면 어떻게 될까요?

보통 dependency 배열에 들어온 값이 이전과 비교해 달라졌으면 리렌더링을 수행합니다.

하지만 배열이나 객체의 내부 속성값이 바뀌어도 변화가 일어나지 않습니다.

이는 자바스크립트에서 비교연산을 얕은 비교방식으로 수행하기에 일어나는 현상입니다.

 

이를 해결하기 위해서는 해당 객체를 JSON.stringify를 이용해 string으로 바꾸어 값을 넣어주던가, 

use-deep-compare-effect라는 라이브러리를 이용하면 됩니다.

그래도 위 방법도 어찌보면 비효율적이기에, 변화를 감지할 속성을 직접적으로 명시해주는게 베스트인거 같습니다.

 

 

 

컴포넌트명이 대문자로 시작해야하는 이유는 뭘까요?

JSX 태그 이름 컨벤션에 해당됩니다.

자바의 객체지향 클래스 네이밍 컨벤션을 따라 컨벤션을 정한것 같습니다.

 

 

 

setState를 호출하지 않고 컴포넌트를 리렌더링 하는 방법이 있는가?

component.forceUpdate(callback) 을 이용해 할 수 있습니다.

하지만 setState와 는 다르게, shouldComponentUpdate()를 생략합니다.

그리고 공식에선 forceUpdate 사용을 지양하는 것을 권장합니다.

 



리액트 폴더 구조를 나누는 방법이 있는가

리액트는 정석적인 폴더 구조를 나누는 방법은 없습니다.

그래도 개인적으론, 비슷한 관심사를 가진 파일들끼리 모아두는 방식으로 구현하려 합니다.

// 개인적으로 현재 사용하고 잇는 컴포넌트 디렉터리 구조

[component]
  - component.js
  - component.styles.js
  [hooks]
    - useCustomHook.js   // 현재 컴포넌트에서 사용하는 커스텀 훅 파일 (뷰와 로직을 분리하기 위한 목적)
    - ...