함께 성장하는 프로독학러
Memo_app 09. 성능 개선 본문
안녕하세요, 프로독학러 입니다.
이번 포스팅에서는 지금까지 만든 어플리케이션의 성능을 개선해 보도록 하겠습니다.
*본 튜토리얼은 Velopert 님의 'React.js Codelab 2016' 을 기반으로 되었습니다.
(여러 모듈들의 버전업에 따라 작성방법이 조금씩 달라진 코드를 버전에 맞게 수정하고, 제가 튜토리얼을 따라함에 있어 이해가 쉽지 않았던 부분에 설명을 추가하는 방식으로 진행합니다.)
* Velopert 님의 원본 튜토리얼을 보고싶으신 분들은 아래의 링크를 참고해 주세요.
<React.js codelab 2016 - Velopert>
1. 성능 개선
현재 모든 기능을 구현이 완료된 상태입니다.
하지만 테스트를 하면서 어플리케이션이 조금 버벅거린다는 느낌을 받진 않으셨나요?
아직 느끼지 못하셨을 수도 있습니다. 그렇다면 스크롤을 마지막 메모가 로딩될 때까지 내려보세요. 그리고 맨 끝에서 위 아래로 이동하는 것을 반복해 보세요. 아마 조금씩 끊기는 듯한 느낌을 받으실 것입니다. (CPU 성능이 좋다면 거의 느껴지지 않으실 수도 있습니다.)
왜 끊기는 느낌이 드는걸까요?
이유를 파악해 봅시다.
1-1) Memo 컴포넌트의 render() 메소드
Memo 컴포넌트 파일을 열고 render() 메소드의 최상단에 아래의 코드를 추가해보세요.
1 | console.log(this.props.data); | cs |
그리고 브라우저에서 콘솔창을 열고 확인해 보세요.
오 이런... 콘솔창에 this.props.data 가 엄청나게 찍히는군요. 스크롤을 할 때마다 이미 렌더링된 컴포넌트에서 render() 메소드가 계속해서 실행됩니다.
메모를 한 번 수정해 보세요. 수정된 Memo 컴포넌트에서만 render() 메소드가 실행되는 것이 아니라 수정되지 않은 다른 Memo 컴포넌트에서도 render() 메소드가 실행되고 있습니다.
그렇다면 이 문제가 발생하는 이유는 무엇일까요?
이는 리덕스 스토어의 API 관련 status 가 업데이트 될 깨도 컴포넌트가 업데이트되기 때문입니다.
(컴포넌트가 다시 렌더링되는 것은 아니지만, render 메소드를 실행하고 변화가 있는지 없는지 계산하기 때문에 render 메소드가 계속해서 실행됩니다)
* 리액트 컴포넌트는 props 나 state 가 변경되면 업데이트되는 특성이 있습니다. 이는 component LifeCycle API 와 관련있습니다. 이에 익숙하지 않으신 분들은 아래의 링크를 참조해 주세요.
1-2) MemoList 컴포넌트 수정
문제점을 해결하기 위해서 먼저 MemoList 컴포넌트를 수정하도록 하겠습니다.
MemoList 컴포넌트의 render 메소드에서는 컴포넌트 매핑을 통해 Memo 컴포넌트를 렌더링하는 복잡한 작업을 수행합니다.
만약 MemoList 의 render 메소드가 필요하지 않을때도 실행된다면 복잡한 컴포넌트 매핑을 계속 해야하므로 어플리케이션이 무거워지겠죠?
한 번 확인해 봅시다.
먼저 Memo 컴포넌트에서 작성했던 console.log 를 잠시 주석처리 해주세요.
그리고 MemoList 컴포넌트의 render() 메소드 최상단에 아래의 코드를 작성해 보세요.
1 | console.log('MemoList render method executed'); | cs |
그리고 브라우저의 콘솔창을 통해 확인해 봅시다.
MemoList 컴포넌트의 render 메소드가 엄청나게 실행되고 있네요...
문제점은 다음과 같습니다.
문제점 1: 5초마다 새 게시물 불러오기를 시도할 때, 새로운 게시물이 없더라도 render 메소드가 2 번 실행된다.
이유: Home 컴포넌트의 listStatus.status 가 'WAITING' 으로 변할 때 한 번, 'SUCCESS' 가 될 때 한 번.
문제점 2: 스크롤을 통해 이전 메모를 불러올 때 render 메소드가 4 번 실행된다.
이유: Home 컴포넌트의 무한스크롤링을 위한 state.loadingStatus 가 토글 되면서 한 번, listStaus 가 'WAITING' 으로 변할 때 한 번, 'SUCCESS' 될 때 한 번, Home 컴포넌트에서 새 데이터를 전달받을 때 한 번 (props.memoData)
MemoList 컴포넌트가 전달받은 props 가 변경될 때 render 메소드가 트리거됩니다.
* 트리거는 어느 특정한 동작에 반응해 자동으로 필요한 동작을 실행하는 것을 뜻한다. from 위키백과
그리고, 전달받은 props 에 변화가 없더라도 페어런트 컴포넌트 (Home) 에서 render 메소드가 실행될 때도 MemoList 의 render 메소드가 실행됩니다. (Home 에서 컴포넌트 state 가 변하면 render 메소드 실행)
이를 막기 위해서는 LifeCycle API 인 shouldComponentUpdate 를 이용하면 됩니다.
* 이에 익숙하지 않으신 분들은 아래의 링크를 참조해 주세요.
(./src/components/MemoList.js)
1 2 3 4 5 6 7 | ... shouldComponentUpdate(nextProps, nextState) { // 리턴값이 true 이면 render 메소드 실행 let update = JSON.stringify(this.props) !== JSON.stringify(nextProps); return update; } ... | cs |
shouldComponentUpdate 는 리턴값이 true 이면 render 메소드를 실행합니다.
4 번째 줄에서 shouldComponentUpdate 의 인자로 들어온 nextProps 와 현재의 props 를 비교하여 달라진게 있다면 render 메소드를 실행하도록 합니다. (Header 로 부터 전달 받은 props)
MemoList 의 render 메소드 안에서 정의한 console.log 화면이 새로운 메모 리스트 데이터를 받아 올 때만 출력되는 것을 알 수 있습니다.
1-3) Memo 컴포넌트 수정
Memo 컴포넌트는 MemoList 가 렌더될 때 렌더링 되므로 Memo 컴포넌트에도 shouldComponentUpdate API 를 추가해 줍시다.
(./src/components/Memo.js)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ... shouldComponentUpdate(nextProps, nextState) { let current = { props: this.props, state: this.state }; let next = { props: nextProps, state: nextState }; let update = JSON.stringify(current) !== JSON.stringify(next); return update; } ... | cs |
이번에는 props 뿐만 아니라 state 도 같이 비교했습니다.
shouldComponentUpdate 를 추가한 뒤, Memo 에서 주석처리했던 console.log 를 주석해제 한 뒤 테스트 해 보세요.
state 가 변경될 때, props 로 전달 받은 메모 리스트 데이터가 추가 될 때만 render 메소드가 실행되는 것을 알 수 있습니다.
작업이 끝나면 console.log 들을 지워주세요.
스크롤이 훨씬 부드러워 지신것을 느끼셨나요?
여기까지...
어플리케이션의 성능을 개선해 보았습니다.
다음 포스팅에서는 지금까지 만들 어플리케이션을 배포 하기위한 build 를 하고 몇 가지 버그를 수정해 보도록하겠습니다.
감사합니다.
**참고 자료 (항상 감사드립니다)
*이 포스팅이 도움이 되셨다면 다녀가셨다는 표시로 공감 부탁드릴게요! (로그인 하지 않으셔도 공감은 가능합니다 ㅎㅎ)
'Programming > tutorials' 카테고리의 다른 글
Memo_app 08. 추가 기능 구현 - 별점, 담벼락, 검색 기능 구현 (0) | 2018.06.28 |
---|---|
Memo_app 07. 메모(Memo) - Update, Delete 기능 구현 (0) | 2018.06.27 |
Memo_app 06. 메모(Memo) - Retrieve 기능 구현 (메모읽기) / 무한스크롤링 구현 (0) | 2018.06.27 |
Memo_app 05. 메모(Memo) - Create 기능 구현 (메모작성) (0) | 2018.06.26 |
Memo_app 04. 인증(authentication) - 로그인, 로그아웃, 로그인 확인 구현 (0) | 2018.06.26 |