[MGS 3기 - 26일차] React 심화 (5)

박철연·2022년 5월 17일
0

MGS STFE 3기

목록 보기
23/35

오늘은 공식 문서를 바탕으로 한 React 심화 과정을 끝냈습니다. 마무리하면서, 기존에 충분히 다루지 못했거나 추가 학습이 필요한 부분에 대해서도 추가하여 정리글을 작성해 보았습니다.

재조정 (Reconciliation)

재조정이란?

React는 선언적 API를 제공하기 때문에, 화면이 새롭게 갱신이 될 때마다 매번 무엇이 바뀌었는지를 굳이 신경 써주지 않아도 됩니다.

물론 이것이 웹 어플리케이션의 작성을 쉽게 만들어주지만, React 내부에서 어떤 일이 일어나고 있는지는 명확히 알려주지 않는다는 것은 단점으로 작용합니다.

재조정(Reconciliation)은 우리가 React의 “비교 (diffing)” 알고리즘을 만들 때 어떤 선택을 했는지를 소개하는 기능입니다. 이 비교 알고리즘 덕분에 컴포넌트의 갱신이 예측 가능해지면서도 성능적으로 충분히 빠른 앱을 만들 수 있습니다.

리액트를 처음 소개할 때, 가상 DOM을 활용하여 효과적인 화면 갱신을 한다고 설명한 바 있습니다. 재조정은 이러한 과정을 효과적으로 만들어주는 개념이라고 볼 수도 있겠습니다.

비교 알고리즘

엘리먼트의 타입이 다른 경우

두 루트 엘리먼트의 타입이 다르면, React는 이전 트리를 버리고 완전히 새로운 트리를 구축합니다. a 태그 에서 img로, Article에서 Comment로, 혹은 Button에서 div로 바뀌는 것 모두 트리 전체를 재구축하는 경우입니다.

트리를 버릴 때 이전 DOM 노드들은 모두 파괴됩니다. 컴포넌트 인스턴스는 componentWillUnmount()가 실행됩니다. 새로운 트리가 만들어질 때, 새로운 DOM 노드들이 DOM에 삽입됩니다.

그에 따라 컴포넌트 인스턴스는 UNSAFE_componentWillMount()가 실행되고 componentDidMount()가 이어서 실행됩니다. 이전 트리와 연관된 모든 state는 사라집니다.

루트 엘리먼트 아래의 모든 컴포넌트도 언마운트되고 그 state도 사라집니다. 예를 들어, 아래와 같은 비교가 일어나면, 이전 Counter는 사라지고, 새로 다시 마운트가 될 것입니다.

<div>
  <Counter />
</div>
<span>
  <Counter />
</span>

DOM 엘리먼트의 타입이 같은 경우

같은 타입의 두 React DOM 엘리먼트를 비교할 때, React는 두 엘리먼트의 속성을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 갱신합니다.

<div className="before" title="stuff" />

<div className="after" title="stuff" />

이 두 엘리먼트를 비교하면, React는 현재 DOM 노드 상에 className만 수정하는 식으로 동작합니다.

Ref

Ref의 개념

Ref는 render 메서드에서 생성된 DOM 노드나 React 엘리먼트에 접근하는 방법을 제공합니다.

일반적인 React의 데이터 플로우에서 props는 부모 컴포넌트가 자식과 상호작용할 수 있는 유일한 수단입니다. 자식을 수정하려면 새로운 props를 전달하여 자식을 다시 렌더링해야 하는 것이죠.

하지만, 일반적인 케이스에서 벗어나 직접적으로 자식을 수정해야 하는 경우도 가끔씩 있습니다. 수정할 자식은 React 컴포넌트의 인스턴스일 수도 있고, DOM 엘리먼트일 수도 있습니다.

React는 두 경우 모두를 위한 해결책을 제공하는데, 그것이 바로 ref인 것입니다.

Ref를 사용하는 경우

리액트에서 ref를 사용하는 경우는 다음과 같습니다.

  1. 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때
  2. 애니메이션을 직접적으로 실행시킬 때
  3. 서드 파티 DOM 라이브러리를 React와 같이 사용할 때

하지만, ref는 애플리케이션에 “어떤 일이 일어나게” 할 때 사용될 수도 있습니다. 그럴 때는 어느 컴포넌트 계층에서 상태를 소유해야 하는지 신중하게 고려하여 ref를 사용해야 합니다.

ref 사용해보기

Ref는 React.createRef()를 통해 생성되고 ref 어트리뷰트를 통해 React 엘리먼트에 부착됩니다.

보통, 컴포넌트의 인스턴스가 생성될 때 Ref를 프로퍼티로서 추가하고, 그럼으로서 컴포넌트의 인스턴스의 어느 곳에서도 Ref에 접근할 수 있게 합니다.

생성 예시는 아래와 같습니다.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

render 메서드 안에서 ref가 엘리먼트에게 전달되었을 때, 그 노드를 향한 참조는 ref의 current 어트리뷰트에 담기게 됩니다.

따라서 ref에 접근하는 것은 다음과 같은 방식으로 수행할 수 있습니다.

const node = this.myRef.current;

정적 타입 검사

저번 정리글에서 요약한 바와 같이, 리액트에서는 타입 체킹을 수행할 수 있는 다양한 수단이 존재합니다.

가장 대표적인 것은 TypeScript일 것이고, 리액트에서 제공하는 Proptypes로도 타입 검사가 가능합니다. 이번 정리글에서는 또다른 정적 타입 검사 수단인 Flow에 대해서 간단하게 정리해보겠습니다.

Flow 소개

Flow는 JavaScript 코드를 위한 정적 타입 체커입니다. 페이스북에서 개발했으며, 보통 React와 함께 사용합니다.

특별한 타입 문법을 사용하여 변수, 함수 및 React 컴포넌트에 주석을 달 수 있고, 에러를 조기에 발견할 수 있습니다.

Flow를 사용하기 위해서는 아래 요구 사항을 만족 해야 합니다.

  • Flow를 프로젝트 의존성에 추가합니다.
  • 컴파일된 코드에서 Flow 문법이 제거되었는지 확인합니다.
  • 타입 주석을 추가하고, 타입을 체크하기 위해 Flow를 실행합니다.

Flow 설치/시작하기

우선, 터미널을 통해 프로젝트 디렉토리로 들어간 뒤 다음 명령어를 실행해서 Flow를 설치해야 합니다.

$ npm install --save-dev flow-bin

그런 다음, Flow를 사용하기 위해서 package.json 파일의 "scripts" 부분에 "flow"라고 추가해줘야 합니다.

{
  // ...
  "scripts": {
    "flow": "flow",
    // ...
  },
  // ...
}

터미널에 아래 명령어를 입력하면, Flow가 제대로 설치되고 실행되는지 확인할 수 있습니다.

$ npm run flow

// 이 문구가 나타난다면 제대로 동작하는 것입니다.

No errors!
✨  Done in 0.17s.

Flow 문법 주석으로 실습해보기

Flow는 코드 주석을 위한 특별한 문법과 함께 JavaScript 언어를 확장합니다.

하지만 브라우저는 이 문법을 알아차리지 못하기 때문에 컴파일된 JavaScript 번들을 브라우저에 보내기만 하고 끝내서는 안됩니다. 이 작업을 수행하기 위한 방법은 JavaScript를 컴파일하는 데 사용하는 도구에 따라 달라집니다.

기본적으로 Flow는 다음 주석이 포함된 파일만 체크합니다.

// @flow

대체적으로 위 주석은 파일 최상단에 둡니다. 프로젝트의 몇몇 파일에 주석을 추가하고 yarn flow 나 npm run flow 명령어를 실행하여 Flow가 어떤 문제를 찾아냈는지 확인해볼 수 있습니다.

주석에 상관없이 모든 파일들을 체크하는 옵션도 있습니다. 이미 존재하는 프로젝트에 적용하는 것은 어렵겠지만 모든 타입을 체크하고자 하는 새로운 프로젝트에는 적합합니다.

profile
Frontend Developer

0개의 댓글