일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- vscode
- 프로그래머스
- 응답코드
- input 안보임
- lazy-load
- CRA
- git 명령어
- CRLF
- 참조타입
- git
- git autocrlf
- LF
- password 안보임
- expected linebreaks to be 'crlf' but found 'lf' linebreak-style
- 개행문자
- expected linebreaks to be 'lf' but found 'crlf' linebreak-style
- prettier
- eslint-prettier
- input type password
- k번째수
- git 개행문자
- 퀵정렬
- eslint
- HTTPS
- IP주소
- REST API
- 원시값
- 가장큰수
- JadenCase
- react
- Today
- Total
우파루파의 개발 기록
[React.js] Shallow compare와 Class component에서의 최적화 (22.04.13. 내용 수정 및 추가) 본문
[React.js] Shallow compare와 Class component에서의 최적화 (22.04.13. 내용 수정 및 추가)
upa-r-upa 2021. 6. 17. 22:44
들어가며
안녕하세요. 이번 포스팅에서는 Shallow compare 와 Class component 에서의 최적화에 대해 말씀드리려고 합니다.
메모리에 대한 이해가 있으시면 좀 더 쉽게 이해하실 수 있습니다. 물론 없어도 무관 합니다.
최적화란 무엇일까요?
최적화란 말 그대로 성능을 개선하여 가장 적은 비용으로 가장 좋은 퍼포먼스를 낼 수 있도록 하는 것입니다.
들어는 봤는데, 너무 어렵지 않나요?
'Webpack을 이용하여 build한 파일을 경량화하고, 의존성을 파악하여 코드 스플리팅을 진행하고.. '
맞습니다. 최적화는 깊이 파고들면 어려운 방식들이 가득합니다.
하지만 위와 같이 어려운 작업은 하나씩 천천히 진행하면 됩니다.
너무 어려운 작업 말고, 작업 중에서도 가장 쉽게 접근할 수 있는 방법에 대해 설명해 드릴 테니까요! 잘 따라와 주시기 바랍니다.
Class 컴포넌트 최적화 방법엔 어떤 것이 있을까요?
Class 컴포넌트의 최적화 방식은 대표적으로 2가지를 말씀 드릴 수 있을 것 같습니다.
바로 shouldComponentUpdate method, PureComponent 입니다! 예상하셨듯이 오늘 포스팅할 주요 내용도 위 두 가지입니다.
두 가지 항목을 알아보기 전, 먼저 JS의 자료형 별 특징에 대해서 알아야 합니다.
참조 타입과 원시 데이터 형식의 특징
JS의 데이터 타입에는 string, number, boolean, array 등 여러 가지 형식이 있습니다.
참조 타입과 원시 데이터 형식의 메모리 저장 방식은 메모리에 대한 이해가 조금 필요한데요, 지금은 간단하게 알려 드리겠습니다.
형식별로 A 변수를 선언 후 B 변수로 복사할 때 동작하는 방법을 보여드리며 설명드리겠습니다.
원시 데이터 형식의 경우 (Immutable)
let a = 10;
let b = a;
console.log(a, b);
// 출력: 10, 10
a = 5;
console.log(a, b);
// 출력: 5, 10
- a 변수에 10을 할당합니다.
- 단순하게 리터럴만을 저장해두는 저장소와 변수의 선언부를 저장해두는 저장소가 따로 있다고 가정합니다.
- 리터럴 저장소에서 10이라는 리터럴 값을 찾고, 만약 값이 있다면 a라는 변수 선언부 저장소에 해당 값의 메모리 저장소 주소를 쌍으로 묶어 저장합니다. 없다면 리터럴 저장소에 10을 추가하고, 같은 과정을 진행합니다. - b 변수에 a 값을 [복사] 합니다.
- a 변수가 바라보고 있던 변수 선언부 저장소 > 리터럴 값 저장소 주소를 그대로 복제하여 새로운 선언부 저장소의 메모리에 저장합니다. 이제부터 a와 b는 변수 선언부 저장소의 위치는 다르지만, 리터럴 값 저장소의 위치는 같은 내용을 바라보게 됩니다.
- 이렇게 되면 같은 10이라는 값을 여러 메모리 주소에 저장하지 않게 되어 효율적으로 값을 관리할 수 있습니다. - a 데이터의 값을 5로 변경합니다.
- 해당 과정에선 a 변수가 바라보고 있던 값을 직접 수정하지 않습니다. 1번 과정을 비슷하게 반복합니다.
5라는 값을 리터럴 저장소에서 들고 있는지 확인한 이후, 만약 값이 있다면 ... (1번 뒷부분 반복) 하게 됩니다. - 이렇게 되면 값을 아무리 변경하더라도, 값을 수정하는 것이 아닌 리터럴 저장소에서 값을 찾아 그 주소를 연결시켜주기 때문에 각 데이터에 영향이 없습니다
참조 타입의 경우 (Mutable)
let a = { value: 10 };
let b = a;
console.log(a, b);
// 출력: { value: 10 }, { value: 10 }
a.value = 5;
console.log(a, b);
// 출력: { value: 5 }, { value: 5 }
- a 변수에 객체를 할당합니다.
- 단순하게 리터럴만을 저장해두는 저장소와 변수의 선언부를 저장해두는 저장소가 따로 있다고 가정합니다.
- a 변수의 { value: 10 } 값은 선언 시 리터럴 저장소에 새로이 추가됩니다. 그리고 리터럴 저장소 메모리 주소를 변수 선언부 저장소 영역에 저장하게 되고, a 변수는 이러한 리터럴 저장소의 특정 위치를 바라보게 됩니다. - b 변수에 a 값을 할당합니다.
- a 변수가 바라보고 있던 리터럴 저장소의 값을 - a 변수의 value의 값을 5로 변경합니다.
- a 변수의 'value' 값을 변경하게 됩니다.
- 같은 값을 바라보고 있던 b도 변경된 값을 바라보게 됩니다. - 참조 형식의 경우, `b = a` 와 같은 형식으로 복사하게 되면(이걸 얕은 복사라고 합니다.) 결국 같은 메모리 주소를 바라보게 되기 때문에 값을 수정했을 때 서로에게 영향을 끼칩니다. 그
이와 같은 특징 때문에 참조 형식의 경우 내부의 깊은 값이 변경된다고 해도, 객체 자체의 메모리 주소는 같기 때문에 변경되지 않았다고 판단하는 불상사가 있을 수 있습니다.
shouldComponentUpdate method
shoudComponentUpdate 메서드는 React Component의 내장 메서드입니다.
컴포넌트가 리 렌더링 되기 전에 호출되는 메서드로, boolean 값을 return 합니다.
메서드에서 return 되는 값을 기준으로 리 렌더링의 여부를 결정합니다.
return 되는 값이 참이라면 리 렌더링을 진행하고, 거짓이라면 리렌더링을 하지 않습니다.
컴포넌트의 리 렌더링은 Props나 State가 변경되었을 때나, 부모 컴포넌트가 리 렌더링 될 때 발생합니다.
그 이유로 위 메서드는 기본적으로는 항상 true를 return 하기 때문입니다.
컴포넌트의 값이 유효하게 업데이트되지 않았는데도 불필요하게 리 렌더링이 일어난다면 당연히 성능상의 이슈가 발생할 수 있겠죠?
그러나 걱정 마세요! 이 메서드를 잘 사용하면 원하는 조건에서만 컴포넌트가 리렌더링 되도록 설정하여 최적화를 진행할 수 있어요.
다음과 같은 코드로 구현할 수 있습니다.
아래 코드는 props의 [김다빈]이라는 값이 변경되는 경우만 rerendering 하도록 합니다
shouldComponentUpdate(nextProps, nextState) {
// 파라미터로 next props와 next state가 들어옵니다.
if (this.props.김다빈 !== nextProps.김다빈) {
return true;
} else {
return false
}
}
위 코드에선 props로 전달되는 김다빈이라는 값을 비교해서 실제로 변경됐을 때만 리 렌더링이 일어나도록 하고 있습니다.
그런데, 분명 잘 동작할 것이고 이걸 이용하면 최적화도 할 수 있는 게 맞는데.. 뭔가 귀찮습니다.
우리는 단순하게 컴포넌트에 전달되는 props나 state가 변경됐을 경우에만 리 렌더링 하고 싶은 건데, 그렇다면 props와 state들을 하나하나 if문으로 변경됐는지 처리해줘야 하는 걸까요?
아닙니다! 이걸 자동으로 처리해주는 좋은 친구가 있습니다.
바로, React.PureComponent입니다.
React.PureComponent
어디서 들어보신 분들도 계실 텐데요, 네 맞습니다. 이 친구가 바로 귀찮은 일을 어느 정도 해줄 수 있는 귀여운 친구입니다.
PureComponent는 에서 내부적으로 shoudComponentUpdate 메서드를 미리 구현해 Props나 State가 변경이 됐는지를 얕은 비교를 통해 검증하여 리렌더링을 할 수 있게 해줍니다.
그 대신, 일반 Component 처럼 shoudComponentUpdate 메서드를 오버라이딩 할 수 없습니다.
여기서 언급되는 얕은 비교란 간단하게 말씀 드리면 다음과 같습니다.
얕은 비교란?
- 원시 타입의 경우는 값 자체를 비교합니다.
- 참조 타입의 경우는 메모리 주소를 비교합니다.
제가 왜 어느정도 대신 해 줄 수 있다 라는 부분을 강조했는지 눈치 채신 분이 계실까요?
혹시 맞추셨다면 칭찬 드리고 싶습니다. 이유는, 얕은 비교를 진행하기 때문에 원시 타입의 데이터가 아니라면 값이 진짜 변경 됐는지를 정확하게 판단할 수 없게 됩니다.
그러니 PureComponent를 사용하실 때는 업데이트 됐는지 검증 하고자 하는 값이 참조 타입의 값인 경우는 써도 의미가 없을 수 있습니다. 이 부분을 신경쓰지 않고 아무 컴포넌트에서나 PureComponent를 남용하게 되면, 제대로 업데이트가 되어야 하는 순간에 업데이트가 되지 않았다고 판단하여 오히려 나쁜 결과를 초래할 수 있습니다.
마치며
이번 포스팅에서는 Class 컴포넌트의 최적화와 이를 이해하는 데 필요한 내용들을 부수적으로 알아보았습니다.
아무래도 메모리에 대한 내용이 자주 나왔습니다. 곧 메모리에 대한 자세한 내용을 다루도록 노력 해보겠습니다.
글을 읽으시며 이해가 어려우셨던 부분이나 잘못된 부분이 있으면 코멘트로 남겨주세요. 감사합니다.
+ 2022.04.13. 메모리 관련 내용을 좀 더 정확하게 수정하였습니다.
'development > React' 카테고리의 다른 글
[React.js] 요즘 잘 사용하고 있는 VSCode에서의 Typescript ESLint/Prettier 환경 함께 설정하기 (0) | 2022.10.08 |
---|---|
[Gatsby.js] Gatsby+Typescript에서 styled-component 본격 설정하기 (0) | 2022.09.30 |
[React.js] Styled Components 간단 정리 [Basic] (0) | 2021.06.24 |
[React.js] ESLint와 Prettier를 이용한 React 환경 설정 (VSCode) (0) | 2021.06.19 |
CRA를 이용해서 Typescript 프로젝트 만들기 (+ 유사 절대 경로 설정하기(vsCode)) (0) | 2020.05.21 |