1.1 자바스크립트의 동등 비교
의존성 배열에 대한 고민 : 보통 리액트에서 제공하는 eslint-react-config에 선언돼 있는 react-hooks/exhaustive-deps의 도움을 받아 해당 배열을 채우는데, 실제로 이것이 어떤 식으로 작동하는지, 또한 왜 이러한 변수들을 넣어야 하는지 이해하지 못하는 경우가 많음
렌더링 관점 : 리액트 컴포넌트의 렌더링이 일어나는 이유 중 하나가 바로 props의 동등 비교에 따른 결과
리액트의 가상 DOM과 실제 DOM의 비교, 리액트 컴포넌트가 렌더링할지를 판단하는 방법, 변수나 함수의 메모이제이션 등 모든 작업은 자바스크립트의 동등 비교를 기반으로 함
1.1.1 자바스크립트의 데이터 타입
원시타입 (primitive type) |
boolean | 참과 거짓만을 가질 수 있는 데이터 타입 |
null | 아직 값이 없거나 비어 있는 값을 표현할 때 사용 | |
undefined | 선언한 후 값을 할당하지 않은 변수 또는 값이 주어지지 않는 인수에 자동으로 할당되는 값 | |
number | 모든 숫자를 하나의 타입에 저장 | |
string | 텍스트 타입의 데이터 저장 | |
symbol | 중복되지 않는 어떠한 고유한 값을 나타내기 위해 만들어짐 | |
bigint | number의 한계를 넘어서 더 큰 숫자를 저장 | |
객체타입 (object/reference type) |
object | 자바스크립트를 이루고 있는 대부분의 타입 배열, 함수, 정규식, 클래스 등이 포함 |
- 후술한 원시값 중 null과 undefined는 오직 각각 null과 undefined라는 값만 가질 수 있으며, 그 밖의 타입은 가질 수 있는 값이 두 개 이상 존재
- 다른 원시값과 다르게 typeof로 null을 확인했을 때 해당 타입이 아닌 'object'라는 결과 반환
- 자바스크립트 문자열은 원시 타입이며 변경 불가능
1.1.2 값을 저장하는 방식의 차이
원시 타입
- 불변 형태의 값으로 저장
- 변수 할당 시점에 메모리 영역을 차지하고 저장
let hello = 'hello world'
let hi = hello
console.log(hello === hi) // true
객체 타입
- 프로퍼티를 삭제, 추가, 수정할 수 있으므로 원시 값과 다르게 변경 가능한 형태로 저장
- 값을 복사할 때도 값이 아닌 참조를 전달
var helllo = {
greet: 'hello, world',
}
var hi = {
greet: 'hello, world',
}
console.log(hello === hi)
console.log(hello.greet === hi.greet) // false
자바스크립트 개발자는 항상 객체 간에 비교가 발생하면, 이 객체 간의 비교는 우리가 이해하는 내부의 값이 같다 하더라도 결과는 대부분 true가 아닐 수 있다는 것을 인지해야 함
1.1.3 자바스크립트의 또 다른 비교 공식, Object.is
Object.is
- 리액트에서 사용하는 동등 비교는 ==나 ===가 아닌 Object.is
리액트에서의 비교를 요약하자면 Object.is로 먼저 비교를 수행한 다음에 Object.is에서 수행하지 못하는 비교, 즉 객체 간 얕은 비교를 한 번 더 수행하는 것을 알 수 있음
// Object.is는 참조가 다른 객체에 대해 비교 불가능
Object.is({hello: 'world'}, {hello: 'world'}) // false
// 리액트 팀에서 구현한 shallowEqual은 객체의 1 depth까지는 비교 가능
shallowEqual({ hello: 'world'}, { hello: 'world' }) // true
// 그러나 2 depth까지 가면 이를 비교할 방법이 없으므로 false를 반환
shallowEqual({ hello: { hi: 'world'}), { hello: { hi: 'world'} }) // false
객체의 얕은 비교까지만 구현한 이유?
type Props = {
hello: string
}
function HelloComponent(pops: Props) {
return <h1>{props.hello}</h1>
}
// ...
function App() {
return <HelloComponent hello="hi!" />
}
- 리액트에서 사용하는 JSX props는 객체이고, 여기에 있는 props만 일차적으로 비교하면 되기 때문
- 리액트는 props에서 꺼내온 값을 기준으로 렌더링을 수행하기 때문에 일반적인 케이스에서는 얕은 비교로 충분할 것
- props에 또 다른 객체를 넘겨준다면 리액트 렌더링이 예상치 못하게 작동한다는 것을 알 수 있음
pops가 깊어지는 경우, 즉 한 객체 안에 또다른 객체가 있을 경우 컴포넌트에 실제로 변경된 값이 없음에도 불구하고 메모이제이션된 컴포넌트를 반환하지 못함
만약 내부에 있는 객체까지 완벽하게 비교하기 위한 재귀문까지 넣었다면?
객체 안에 객체가 몇 개까지 있을지 알 수 없으므로 이를 재귀적으로 비교하려 할 경우 성능에 악영향을 미칠 것
1.1.5 정리
- 자바스크립트에서 객체 비교의 불완전성은 스칼라나 하스켈 등의 다른 함수형 언어에서는 볼 수 없는 특징
- 자바스크립트를 기반으로 한 리액트의 함수형 프로그래밍 모델에서도 이러한 언어적인 한계를 뛰어넘을 수 없으므로 얕은 비교만을 사용해 비교를 수행
참고
https://product.kyobobook.co.kr/detail/S000210725203
'읽은 책들 > 모던 리액트 DeepDive' 카테고리의 다른 글
[모던 리액트 Deep Dive] 1장. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (0) | 2024.11.07 |
---|---|
[모던 리액트 Deep Dive] 1장. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (0) | 2024.11.04 |
[모던 리액트 Deep Dive] 1장. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (0) | 2024.11.01 |
[모던 리액트 Deep Dive] 1장. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (3) | 2024.10.31 |
[모던 리액트 Deep Dive] 1장. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (1) | 2024.10.30 |