Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
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 31
Tags more
Archives
Today
Total
관리 메뉴

개발의변화

모던리액트딥다이브 - 01 동등비교 본문

프론트엔드

모던리액트딥다이브 - 01 동등비교

refindmySapporo 2024. 3. 27. 10:31
반응형

자바스크립트 동등비교

리액트로 코드를 짜다보면 렌더링의 문제가 골치 아픈데 특히 props의 변화를 체크하는 일이 쉽지 않았다.

props의 동등비교는 객체의 얕은 비교(Shallow Copy)를 기반으로 이뤄지는데, 이 얕은 비교를 리액트가 어떻게 이해하는 지를 알아야 렌더링 문제를 잡을 수 있다.

1.1 자바스크립트 데이터 타입

자바스크립트는 총 7개의 원시타입과 1개의 객체타입을 가지고 있다.

underfined : 변수를 선언한 후 값을 할당하지 않은 변수에 자동으로 할당되는 값

let foo;

typeof foo === undefined; // true

function bar(hello) {
    return hello;
}

typeof bar() === 'undefined' // true

null: 아직 값이 없거나 비어 있는 값을 표현할 때 사용

type null === 'object'

null을 object로 반환이 된다는 점이다.

즉 null은 명시적으로 비어있음을 나타내는 것이고 undefined는 선언됐지만 할당되지 않는 값으로 판단하면 된다.

boolean :

false = 0,false, -0, 0n, 0x0n, '',"",null,undefined
true = 그 외 나머지

number: -2의 53제곱 + 1 ~ 2의 53제곱 - 1
bigint: 2의 53제곱 - 1 이상의 값을 나타낼 때

string :
문자열이 원시타입이며 변경 불가능하다.
문자열이 생성되면 그 문자열을 변경할 수 없음을 의미

const foo = 'bar'
foo[0] = f;
console.log(foo) // bar

symbol:
중복되지 않는 어떠한 고유한 값을 나타내기 위해만들어졌다.

object

객체는 참조값으로 이루어져 있기에 동등비교시 주의해야 한다.
Object.is(인수1,인수2)

  • == vs Object.is: == 비교는 같음을 비교하기 전에 양쪽이 같은 타입이 아니라면 비교할 수 있도록 강제로 형변환 한 후에 변경
    따라서 5 == '5'와 같이 형변환 후에 값이 동일하다면 ==는 true를 반환, Object.is는 이러한 작업 x
-0 === +0 // true
Object.is(-0,+0) // false

Number.NaN === Nan //false
Object.is(Number.NaN, NaN) // true

그렇다면 리액트에서는 어떻게 비교를 하고 있을까

shallowequal 함수를 활용한 동등비교를 지원하고 있다.

import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';

/**
 * Performs equality by iterating through keys on an object and returning false
 * when any key has values which are not strictly equal between the arguments.
 * Returns true when the values of all keys are strictly equal.
 */
function shallowEqual(objA: mixed, objB: mixed): boolean {
  if (is(objA, objB)) {
    return true;
  }

  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  // Test for A's keys different from B.
  for (let i = 0; i < keysA.length; i++) {
    const currentKey = keysA[i];
    if (
      !hasOwnProperty.call(objB, currentKey) ||
      // $FlowFixMe[incompatible-use] lost refinement of `objB`
      !is(objA[currentKey], objB[currentKey])
    ) {
      return false;
    }
  }

  return true;
}

export default shallowEqual;

리액트 팀에서 구현한 shallowEqual은 객체의 1depth까지는 비교 가능

shallowEqual({hello:'world'}, {hello: 'world' })

얕은 비교까지만 구현한 이유는 props만 일차적으로 비교하면 되기 때문이다.

type Props = {
    hello: string
}

function HelloComponent{props: Props){
 return <h1> {hello} </h1> 
}

function App() {
  return <HelloComponent hello = "hi!" />
}

깊은 비교를 제공하지 않는 이유는 props가 객체 안에 객체가 몇개 있을지 알 수 없기에 재귀적으로 비교할 경우 악영향을 미치기 때문이다.

반응형