Skip to content

Latest commit

 

History

History
124 lines (69 loc) · 6.93 KB

React 관련.md

File metadata and controls

124 lines (69 loc) · 6.93 KB

React 관련

프론트엔드 개발을 더 쉽게 만들어주는 library이다.

리액트가 해결하려는 문제

  • 컴포넌트별로 구분하여 유지보수를 용이하게 함
  • Virtual-DOM을 사용하여 사용자의 액션에 따른 수정사항들을 적은 비용으로 적용

Virtual DOM 을 사용하는 이유

Virtual DOM 이란?

→ 실제 DOM의 구조와 비슷한 React 객체의 트리

→ 개발자가 Virtual DOM을 제어하면 React에서 적절한 과정을 통해 Virtual DOM을 DOM에 반영한다.

장점

  • DOM을 직접 조작하지 않아도 된다
  • 수개의 DOM을 직접 관리, 조작하는 과정은 복잡하고 실수할 가능성, 연산비용 등 고려할 게 많은데 Virtual DOM이 이러한 과정들을 자동화, 추상화 해준다
  • DOM 의 update를 batch 작업(실시간 처리가 아닌, 일괄적으로 모아서 처리하는 작업)을 통해 연산을 최소화, 연산을 묶어서 한 번에 처리

Real DOM의 경우에는 업데이트 할 때마다 수정되는 DOM과 관련있는 모든 자식 노드, 부모 노드를 업데이트를 해야한다. 반복해서 업데이트하거나 DOM트리가 클 경우 성능에 나쁜 영향을 끼친다. React는 Virtual DOM을 사용하여 트리의 변경되는 부분만 업데이트하는 방식(diffing algorithm)으로 DOM을 업데이트 하기 때문에 성능면에서 우월하다.

React의 렌더링 과정

  1. Virtual DOM 트리를 메모리에 새로 생성
  2. 이전 Virtual DOM 트리와 O(n)의 diffing algorithm을 사용하여 차이점을 파악한다.
  3. 차이점들을 하나로 모아서 실제 DOM에 전달

→ 이로 인해서 실제 DOM의 리렌더링 연산(Reflow, Repaint) 이 단 한 번만 일어나게 되어 큰 성능의 이득을 얻게 된다.

→ 관리하는 state가 많을 수록 변경사항을 추적하는 것보다 새로 생성하여 비교하는 것이 더욱 효율적!

Reconciliation

전체 DOM트리를 탐색하고 비교하는 일반적인 알고리즘은 O(n^3)의 시간복잡도를 갖는다. 그래서 React는 두 가지 가정 아래에서 복잡도를 O(n)에 근사하도록 구현했다.

가정

  1. 서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만든다.
  2. key prop을 통해 어떤 자식 엘리먼트가 변경되지 않아야 할 지 표시해 줄 수 있다. (동일한 key를 갖는 자식만 비교한다) (key는 sibling 사이에서만 유일하면 된다.)

React 함수형 컴포넌트와 클래스형 컴포넌트의 차이점

  1. 함수형 컴포넌트 사용시 메모리에 이점이 있다.
  2. 클래스형 컴포넌트의 경우에는 생명주기 메소드를 사용하여 특정 시점에 코드가 실행되도록 하지만, 함수형 컴포넌트에서는 Hook을 사용하여 생명주기에 원하는 동작을 실행한다.

근본적으로 다른 것은 아니다. 함수형이 조금 더 편할 뿐!

→ 함수형 컴포넌트를 통해 함수형 프로그래밍으로 코드를 작성할 수 있다.

Hook 이란

기존 class 컴포넌트의 문제점

  1. 컴포넌트가 복잡해지면 이해하기 어렵다.
  2. 생명주기 메소드에 관련없는 로직이 쉽게 섞이기에, 버그가 쉽게 발생하고 무결성이 해쳐진다
  3. class 컴포넌트는 JS의 this키워드 동작방식을 제대로 알아야만 했다
  4. 문법제안의 도움이 없을 때 코드를 매우 장황하게 만든다.

위의 문제를 해결하기 위해 Hook 도입

Hook은 함수 컴포넌트에서 React state와 생명주기 메소드를 연동할 수 있게 해주는 함수이다.

  1. 함수 범위 내에 Hook을 둠으로써 JS의 클로저를 활용하여 문제를 해결
  2. 계층의 변화 없이 상태관련 로직을 재사용할 수 있도록 한다.

HOC란

리액트 컴포넌트를 매개변수로 받아서 새로운 리액트 컴포넌트를 리턴하는 함수이다.

React 성능 최적화

리렌더링 조건을 제대로 활용하자

리렌더링의 경우,

  • 부모에서 전달받은 props 가 변경될 때
  • 부모 컴포넌트가 리렌더링 될 때
  • 자신의 state가 변경될 때

발생한다.

  1. useMemo

컴포넌트 내의 어떤 함수가 값을 리턴하는데(연산에) 많은 시간을 소요한다면, 이 컴포넌트가 리렌더링 될 때마다 함수가 호출되면서 많은 시간을 소요하게 될 것이고, 함수의 반환값을 활용하는 하위 컴포넌트가 있다면 그 하위컴포넌트는 매 함수호출마다 새로운 값으로 리렌더링 될 것이다.

useMemo를 사용하면 두번째 parameter로 dependency를 전달할 수 있는데 해당 dependency 값이 변경될 때에만 연산을 수행함으로써 최적화를 할 수 있다.

→ 연산량이 많은 함수의 반환값을 memoization

  1. React.memo (함수형 컴포넌트)

react.memo() 로 래핑할 경우 리액트는 컴포넌트를 렌더링한 뒤 그 결과를 기억하고 있게되어 새롭게 렌더링 하고 이전과 비교하는 과정을 생략할 수 있다. props가 같을 경우에만 적용된다. 가상 DOM과 바뀐 부분 비교생략!

→ props 를 비교할 때는 shallow compare 로써 원시값 타입은 같은 값을 갖는지, 객체나 배열 등은 같은 참조값을 갖는지 확인한다.

→ 컴포넌트를 렌더링 한뒤 그 결과를 memoization

→ ( class형 컴포넌트에서는 React.PureComponent를 사용하자 (똑같이 얕은 비교를 통해서 state나 props의 변경을 인지한다, shouldComponentUpdate 에 얕은비교가 이미 적용되어 있음)

  1. useCallback

인라인 함수를 props로 전달할 경우 re-rendering마다 함수가 메모리에 새로 할당되므로 해당 인라인 함수를 사용하는 컴포넌트가 다시 렌더링 된다.

컴포넌트 내부의 함수들은 리렌더링 시 마다 새로

→ 특정 함수를 새로 만들지 않고 재사용

  1. 자식 컴포넌트의 props로 객체를 넘겨줄 때 데이터 가공을 하위컴포넌트에 위임하기

props의 값으로 객체를 넘겨주는 경우에는 컴포넌트가 리렌더링 될 때마다 새로운 객체가 생성되어 자식컴포넌트로 전달된다. 새로 생성된 객체는 이전 객체와 다른 참조 주소를 가지기 때문에 자식 컴포넌트는 메모이제이션이 되지 않는다.

→ 데이터가공은 하위컴포넌트에서 해서 상위 컴포넌트가 리렌더링 될 때 불필요하게 리렌더되는 상황을 방지하자

  1. key 값으로 index 사용하지 않기

React에서는 key를 사용하여 React element를 식별하고 비교하여 차이점을 새로 그린다. 고유한 id가 아닌 index를 key로 사용한다면 새로운 아이템이 맨 앞에 들어올 경우 index가 하나씩 밀려서 key가 들어간 형제노드들을 전부 update해야한다.

  1. onChange 이벤트처럼 타이핑을 할 때마다 렌더링되는 경우

React 18에서 추가된 Transition 언급!