앞에서 배웠던 컨셉을 조금 정리하고 성능에 대해서 한번 정리해보자.
React는 총 두가지 문장으로 설명할 수가 있는데, 첫번째는 리액트는 Component들이고 두 번째는, 데이터가 조금이라도 업데이트가 되면 전체적으로 어플리케이션이 다 re-render 된다(Re-render the whole app on every update)
react에는 클래스로 만들수 있는 Component와 PureComponent가 있다. 또 함수로 만들 수 있는 Component는 그냥 function을 쓰는 거 memo를 쓰는 거 그리고 React Hook쓰면 함수를 쓰면서 클래스 Component와 같이 state와 라이프사이클 메소드를 이용할 수 있다.
Habit Tracker를 살펴보면 habit tracker에는 인덱스.js 파일이 있는데 이렇게 React DOM이라는 라이브러리를 이용해서
인덱스에 있는 root라는 아이디를 가진 요소와 최상위의 Component를 연결해주는 작업을 해주었고
실제로 사용자의 Component는 App이라는 곳에서 시작한다.
App이라는 컴포넌트에는 state가 있고 이 state에 따라서 어떻게 표기될 건지 UI가 정의된 부분은 Render 함수이다.
render 함수에는 navbar와 habits라는 두 가지의 자식요소가 있고
navbar는 따로 자식 요소가 없는 순수 컴포넌트이고
그리고 habits은 habitaddform이라는 자식요소가 있다.
또 ul 태그 안에는 각각 habit마다 habit이라는 컴포넌트를 보여주는 즉, 리스트에 컴포넌트를 보여주는 자식요소가 들어있다. 각각의 render함수에 로그를 출력해서 컴포넌트의 render함수가 언제 호출되는지 확인 해보면
App을 열고 콘솔 탭을 연다음에 새로고침을 해보면 리프레시를 누르게 되면 사용자가 방금 입력했던 콘솔로그가 출력되는 걸 볼 수 있다.
App, Navbar, Habits 각각의 habit 컴포넌트들의 render 함수가 호출 되는 것을 볼 수 있다. 두 번씩 출력되는 것은
인덱스.js에서 StrictMode를 이용하기 때문이다.
이거를 하게 되면 React가 두 번씩 호출하면서 무언가 한 번 더 호출 했을 때 잘안된건 없는지 그런 것들을 검사 하기 위해 나타나는 것이고 StrictMode를 써도 사용자가 개발하는 중간에만 보여지고 실제로 배포할 때는 두 번씩 되지 않는다.
개발하는 과정에서 발생하는 거라서 무시하고 StrictMode를 지우고 다시 실행하면 하나씩만 나온다.
Eating이라는 것을 추가하면 처음부터 App, Navbar, Habits 각각의 habit 컴포넌트가 출력되는데
여기까지 어플리케이션의 state가 변해서 전부다 자식 요소들이 업데이트 되니까 render 함수가 호출되는데
여기서 클릭을 하게 되면 전체의 컴포넌트가 다 업데이트 된다.
즉 render 함수가 계속해서 호출이 되는 것이다. React는 state나 관련된 props이 변경이 되면 전체 다가 업데이트 된다고 알고 있는데, 그래도 안전한 것은 React 자체에 VDOM, Virtual DOM을 써서 실제로는 정말 업데이트 돼야 되는 것들만 DOM 요소에 업데이트가 되기 때문에 괜찮다고 할 수 있다. 이렇게 Render 함수가 계속해서 호출 됨에도 불구하고 성능이 괜찮은 이유는 HTML에서 태그를 열어본 다음에 클릭을 하면 DOM요소에 전혀 변화가 없다.
ul 태그에도 전혀 변화가 없다. 플러스 버튼누르면 count만 업데이트 되니까 필요한 요소만 업데이트 되고, 나머지는 그대로 있는 것을 볼 수 있다.
즉, React 어플리케이션은 state가 변화되면 전체적으로 Render가 호출이 되는데, 부모의 App에 state가 있게 되고, 그 state가 업데이트 되기 때문에, 그 안에 들어 있는 모든 자식 Component, 또 그 안에 있는 자식 Component 모든 것들이 render가 다시 수행이 되지만, React는 Virtual DOM이라는 메모리상에 이러한 트리를 보관해 놓고 있어서 이전꺼와 업데이트 된 것을 비교하면서 실제로 필요한 부분만 DOM 요소에 업데이트가 되기 때문이다.
그래서 디버깅을 할 때, 콘솔창을 보면서 몇몇 개를 지워보면서 업데이트 되는 것을 확인해보자.
React가 Virtual DOM에서 관리하다가 정말 필요한 경우에는 DOM에 업데이트를 한다.
만약에 Habits Component 안에서, Component가 업데이트 되었을 때마다 호출 해 주는 함수가 있는데, 필요한 기능을 구현해 놓으면 React가 Component가 업데이트 될 때마다 호출 해 주는 함수가 있는데, 유튜브에 있는 데이터를 받아 오던지, 조금 무거운 로직을 수행해야 한다면, 컴포넌트가 업데이트 될 때마다 다른 것을 좀 업데이트 해 주거나 무언가를 해야 되는 일을 하고 있으면 render 함수가 호출 될 때마다 componentDidUpdate()가 호출이 되니까 예상못한 깜빡임이나 불필요한 일들이 수행 될 수 있다. 그래서 React 자체에서 render 함수가 호출이 되어도 DOM 요소를 관리는 해주지만 실제로는 관련된 데이터가 전혀 변경되지 않았음에도 render 함수가 계속 호출 되는 것은 성능에 좋지 않다.
컴포넌트 탭에 와서 설정모양에서 Settings를 눌러서 체크박스를 선택하고 highlight updates when components render 업데이트 되는 것을 하이라이트 해준다. component가 렌더링 될 때, 그래서 이걸 체크 한 다음, 플러스 버튼 누르면 각각 컴포넌트가 업데이트 되는 걸 볼 수 있다.
이거를 방지할 수가 있는 것이 pureComponent와 memo이다. pureComponent와 memo는 컴포넌트에 state나 props에 변화가 없다면, render 함수가 불러지지 않는다. 컴포넌트를 선택한 다음에 Component 대신에 PureComponent를 이용하면 PureComponentsms props과 state 안에 들어 있는 데이터가 최상위에 있는 데이터가 변하지 않으면 render 함수가 호출 되지 않는다. 즉 re-rendering 되지 않는다.
더 이상 re-rendering이 발생하지 않는데, 이 부분이 업데이트 될려면 여기에 전달되는 props나 그 안에서 가지고 있는 state에 데이터에 변경이 되어야 하는데, 여기에는 state가 따로 없고, props을 하나 받고 있다. onAdd라는 콜백함수를 props으로 받는다. onAdd라는 것은 결국 App에서 전달을 받는데
handleAdd는 App이라는 Component가 생길 때 멤버변수가 생길 때 클래스가 만들어질 때 한번 할당된 뒤로 다시는 업데이트가 되지 않는 콜백함수이다. 그래서 props에 변화가 없기 때문에 계속 re-render가 되지 않는 것을 볼 수 있다.
react사이트에 와서
PureComponent는 React의 Component와 비슷한데, 다른점은 Component는 ShouldComponentUpdate()를 구현하지 않았지만 PureComponent는 ShouldComponentUpdate()를 구현했다.라고 나와있는 것을 확인 할 수 있다. ShouldComponentUpdate()는 Component를 업데이트 해야 될지 안 해야 될지 물어보는 함수이다. 구현 사항은 props과 state를 비교한다. shallow 가볍게 비교한다.
즉 Component가 업데이트 되기 전에 React에서 컴포넌트 업데이트 되야하냐 물어보는 함수가 있는데, 컴포넌트는 이 함수를 기본적으로 구현은 안했지만, PureComponent는 함수를 구현해 놓았고 이 함수에 구현사항은 이전에 props나 state를 지금 업데이트된 props나 state를 비교 한다고 나와있다. 비교해서 같으면 업데이트 안해도된다고 false를 리턴하고 업데이트가 필요하면 true를 리턴해서 component가 업데이트 될 수 있도록 해주는 함수가 있다. 여기서 그냥 비교하는게 아니라 shallow 얇게 비교한다라고 되어 있다.
이 말은 오브젝트가 있으면 권재현이라는 것이 있으면 권재현 안에는 name age, 이름과 나이라는 primitive 타입을 가지고 있는 이런 멤버 키가 들어올 수 있지만 또 자녀라는 권재현 오브젝트 안에는 자녀의 오브젝트가 들어있고 자녀 안에난 자녀가 다니고 있는 학교 오브젝트가 있을 수 있다.
이렇게 오브젝트도 트리처럼 뻗어나갈 수 있는데 shallow Comparison 라고 하는 것은 오브젝트의 레퍼런스를 비교한다는 것이다. 오브젝트가 가지고 있는 내부 안에서 데이터가 어떻게 변경 되는 건 상관없고 자녀의 학교가 변경됐든 권재현의 나이가 변경 됐든 동일한 오브젝트 라면 동일한 레퍼런스를 가지고 있는 오브젝트라면 무조건 true가 된다. 그래서 반대로 Depp Comparison은 계속 안에 따라 들어가서 업데이트가 조금이라고 발생하면 똑같이 않다고 말하고
Shallow Comparison은 레퍼런스만 비교해서 안에 데이터가 달라져도 동일한 오브젝트라고 말한다.
props 안에 네가지의 데이터가 있다고 하면 네 가지의 데이터가 다 오브젝트라고 치면 오브젝트 안에 이름이나 다른 사람들이 바뀌어도 동일한 오브젝트라면 render 함수가 호출되지 않는다는 것을 의미
<출처 : DreamCoding 리액트 개념 정리+유튜브 클론코딩: ellie>
참고: https://academy.dream-coding.com/courses/react-basic
리액트 강의 (유튜브 클론 코딩 + 실시간 전송 명함 카드 만들기 웹앱 만들기)
리액트 전반적인 개념 설명과 (클래스 컴포넌트와 함수 컴포넌트 그리고 리액트 훅까지) 실전 유튜브 클론 코딩 프로젝트. Firebas의 실시간 데이터베이스를 이용해 멋진 명함 카드 만들기 웹 어
academy.dream-coding.com
'React > HabitTracker' 카테고리의 다른 글
JS Object 가변성에 대해서(Spread Operator) (0) | 2021.07.31 |
---|---|
PureComponent정리와 차이점 최종 정리 (0) | 2021.07.31 |
Add Form 만들기 (Refs 이용) & Reset buttnon 처리하기 (0) | 2021.07.31 |
App 컴포넌트 만들어 보기(Navbar 컴포넌트 만들기) (0) | 2021.07.31 |
이벤트 처리 하기(업데이트 함수들 구현하기) (0) | 2021.07.31 |