Frontend
자바스크립트와 리액트의 동등 비교
자바스크립트의 동등 비교
리액트 컴포넌트 렌더링이 일어나는 이유 중 하나가 바로 props의 동등 비교에 따른 결과다.
- 렌더링 최적화를 위해서는 리액트 컴포넌트 렌더링이 어떻게 작동하는지 알아야 한다.
- props의 동등 비교가 객체의 얕은 비교 기반으로 이루어진다.
- 가상 DOM과 실제 DOM의 비교, 리액트 컴포넌트가 렌더링할지를 판단하는 방법, 변수나 함수의 메모이제이션 등 모든 작업은 자바스크립트의 동등 비교를 기반으로 한다.
원시 타입(primitive type)과 객체 타입(object/reference)의 차이점
가장 큰 차이점이 바로
값을 저장하는 방식
이다.원시 타입은 불변 형태의 값으로 저장되며, 변수 할당 시점에 메모리 영역을 차지하고 저장된다.
let hello = 'hello world'; let hi = hello; console.log(hello === hi) // true
hello
의hello world
라는 값이hi
에 복사해 전달되었으므로 true가 나온다.
let hello = 'hello world'; let hi = 'hello world'; console.log(hello === hi) // true
- 값을 비교하기 때문에, 값을 전달하는 방식이 아닌 각각 선언하는 방식으로도 동일한 결과가 나온다.
객체 타입은 프로퍼티를 삭제, 추가, 수정할 수 있으므로 변경 가능한 형태로 저장되며, 값을 복사할 때도 값이 아닌 참조를 전달한다.
var hello = { greet: 'hello, world', } var hi = { greet: 'hello, world', } console.log(hello === hi) // false console.log(hello.greet === hi.greet) // true
- 객체는 값을 저장하는 것이 아니라 참조를 저장한다.
var hello = { greet: 'hello, world', } var hi = hello console.log(hello === hi) // true
hi
는hello
와 동일한 주소를 가리키므로true
가 나온다
객체 간 비교가 발생하면, 개발자가 이해하는 객체 내부의 값이 서로 같더라도 결과는 대부분
false
라는 점을 인지해야 한다.자바스크립트의 또 다른 비교 공식, Object.is
동등 비교를 위한 다른 방법으로 자바스크립트에서 제공하는 메서드인
Object.is
와 ==
, ===
의 차이점을 이해하고 있어야 한다.==
- 동등 비교 연산자
- 타입 변환(형 변환, Type conversion)이 일어난 뒤 비교
===
- 엄격한(strict) 동등 비교 연산자
- 타입 변환(Type conversion)이 일어나지 않으며, 타입이 일치해야만 동등한 것으로 간주
Object.is
- 동등 비교 메서드 (ES6+ 이후)
- 동등 비교
==
의 한계를 극복하기 위해 만들어 졌으나, 객체 간 비교에서는===
와 동일하게 동작함
- 사람(개발자)이 이해하는 방식으로 결과를 내주는 경우가 많음
동등 비교 예제
'' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true
-0 === +0 // true Object.is(-0, +0) // false Number.NaN === NaN // false Object.is(Number.NaN, NaN) // true NaN === 0 / 0 // false Object.is(NaN, 0 / 0) // true
var a = {} var b = {} a == b // false a === b // false var c = []; var d = []; c == d // false c === d // false
Object.is({}, {}) // false const a = { hello: 'hi', } const b = a Object.is(a, b) // true a === b // true
리액트에서 동등 비교는
Object.is
메서드를 활용하여 구현되어 있다.리액트에서의 동등 비교
꼭 알아야 할 것들
- JSX Props는 객체로 취급한다.
Object.is
는 참조가 다른 객체 간의 비교가 불가능하다.
- 리액트 팀은
shallowEqual
이라는 메서드를 구현하여 1depth 까지 객체 간 비교가 가능하게 만들었다. Object.is
로 먼저 비교를 수행한 다음Object.is
로 수행하지 못하는 객체 간 얕은 비교를 한 번 더 수행한다.- 리액트 JSX props는 객체이므로, 일차적으로 props만 비교하면 되기 때문에 얕은 비교까지만 구현되었다.
객체 간 얕은 비교(Shallow Comparison)란? 첫 번째 깊이(depth)에 존재하는 값만 비교한다는 것을 의미한다.
예제
type Props = { hello: string } function HelloComponent(props: Props) { return <h1>{hello}</h1> } //... function App() { return <HelloComponent hello="hi!" /> }
- 여기서 props는 객체다.
- 리액트는 props에서 꺼내온 값을 기준으로 렌더링한다.
- 일반적인 케이스에서 얕은 비교로 충분하다.
- 이러한 특성으로 props에 또 다른 객체를 넘겨주면 리액트 렌더링이 예상치 못하게 작동한다.
- 객체 안의 객체는 자바스크립트, 리액트에서 동등 비교가 어렵다는 것을 이해해야 한다.
리액트의 얕은 비교는 객체의 1 depth까지 비교할 수 있게 구현되어 있다는 점을 기억하자. 객체 안의 객체부터는 비교가 불가능하다.
자바스크립트 객체 비교의 불완전성은 다른 함수형 언어에서 볼 수 없는 자바스크립트만의 특징이다. 이러한 언어적 한계를 뛰어넘을 수 없으므로, 리액트는 얕은 비교만을 사용해 필요한 기능을 구현한다는 점을 꼭 숙지하자.