함께 성장하는 프로독학러

Memo_app 09. 성능 개선 본문

Programming/tutorials

Memo_app 09. 성능 개선

프로독학러 2018. 6. 29. 19:23

안녕하세요, 프로독학러 입니다.


이번 포스팅에서는 지금까지 만든 어플리케이션의 성능을 개선해 보도록 하겠습니다.


*본 튜토리얼은 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 와 관련있습니다. 이에 익숙하지 않으신 분들은 아래의 링크를 참조해 주세요.

<component LifeCycle>


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 를 이용하면 됩니다.

* 이에 익숙하지 않으신 분들은 아래의 링크를 참조해 주세요.

<component LifeCycle>


(./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 를 하고 몇 가지 버그를 수정해 보도록하겠습니다.


감사합니다.


**참고 자료 (항상 감사드립니다)

https://velopert.com/1921


*이 포스팅이 도움이 되셨다면 다녀가셨다는 표시로 공감 부탁드릴게요! (로그인 하지 않으셔도 공감은 가능합니다 ㅎㅎ)

Comments