[javascript] 반응에서 얕은 비교는 어떻게 작동합니까?

React 문서 에서는 다음 과 같이 말합니다.

shallowCompare는 현재 상태 및 nextState 객체뿐 아니라 현재 props 및 nextProps 객체에 대해 얕은 동등성 검사를 수행합니다.

내가 이해할 수없는 것은 객체를 얕게 비교하면 shouldComponentUpdate 메서드가 항상 true를 반환합니다.

상태를 변경해서는 안됩니다.

상태를 변경하지 않으면 비교는 항상 거짓을 반환하므로 shouldComponent 업데이트는 항상 참을 반환합니다. 나는 그것이 어떻게 작동하는지 그리고 성능을 향상시키기 위해 이것을 어떻게 재정의 할 것인지에 대해 혼란 스럽습니다.



답변

얕은 비교는 동등성을 확인합니다. 스칼라 값 (숫자, 문자열)을 비교할 때 값을 비교합니다. 객체를 비교할 때 객체의 속성을 비교하지 않습니다. 참조 만 비교됩니다 (예 : “동일한 객체를 가리 킵니까?).

다음 user물체의 모양을 고려해 봅시다

user = {
  name: "John",
  surname: "Doe"
}

예 1 :

const user = this.state.user;
user.name = "Jane";

console.log(user === this.state.user); // true

사용자 이름을 변경했습니다. 이 변경으로도 개체는 동일합니다. 참조는 정확히 동일합니다.

예 2 :

const user = clone(this.state.user);
console.log(user === this.state.user); // false

이제 개체 속성을 변경하지 않고도 완전히 다릅니다. 원본 개체를 복제하여 다른 참조를 사용하여 새 복사본을 만듭니다.

복제 기능은 다음과 같을 수 있습니다 (ES6 구문).

const clone = obj => Object.assign({}, ...obj);

얕은 비교는 변경 사항을 감지하는 효율적인 방법입니다. 데이터를 변경하지 않을 것으로 예상합니다.


답변

얕은 비교는 비교되는 객체의 속성이 “===”또는 완전 동일성을 사용하여 수행되고 속성에 대한 더 깊은 비교를 수행하지 않는 경우입니다. 예를 들어

// a simple implementation of the shallowCompare.
// only compares the first level properties and hence shallow.
// state updates(theoretically) if this function returns true.
function shallowCompare(newObj, prevObj){
    for (key in newObj){
        if(newObj[key] !== prevObj[key]) return true;
    }
    return false;
}
// 
var game_item = {
    game: "football",
    first_world_cup: "1930",
    teams: {
         North_America: 1,
         South_America: 4,
         Europe: 8
    }
}
// Case 1:
// if this be the object passed to setState
var updated_game_item1 = {
    game: "football",
    first_world_cup: "1930",
    teams: {
         North_America: 1,
         South_America: 4,
         Europe: 8
    }
}
shallowCompare(updated_game_item1, game_item); // true - meaning the state
                                               // will update.

두 객체가 모두 동일하게 보이지만은와 game_item.teams같은 참조가 아닙니다 updated_game_item.teams. 두 개체가 동일하려면 동일한 개체를 가리켜 야합니다. 따라서 상태가 업데이트되도록 평가됩니다.

// Case 2:
// if this be the object passed to setState
var updated_game_item2 = {
    game: "football",
    first_world_cup: "1930",
    teams: game_item.teams
}
shallowCompare(updated_game_item2, game_item); // false - meaning the state
                                               // will not update.

이번에는 새 개체와 이전 개체의 팀 속성이 동일한 개체를 가리 키므로 모든 속성이 엄격한 비교를 위해 true를 반환합니다.

// Case 3:
// if this be the object passed to setState
var updated_game_item3 = {
    first_world_cup: 1930
}
shallowCompare(updated_game_item3, game_item); // true - will update

updated_game_item3.first_world_cup속성하면서 1930 엄격한 평가는 숫자에 실패 game_item.first_world_cup문자열입니다. 비교가 느슨하다면 (==) 이것은 통과되었을 것입니다. 그럼에도 불구하고 이것은 상태 업데이트로 이어질 것입니다.

추가 사항 :

  1. 심층 비교를 수행하는 것은 상태 개체가 깊이 중첩 된 경우 성능에 상당한 영향을 미치므로 무의미합니다. 그러나 너무 중첩되지 않았고 여전히 깊은 비교가 필요한 경우 shouldComponentUpdate에서 구현하고 충분한 지 확인하십시오.
  2. 상태 객체를 직접 변경할 수는 있지만 반응하는 setState 메서드 흐름에서 구성 요소 업데이트주기 후크를 구현하기 때문에 구성 요소의 상태는 영향을받지 않습니다. 구성 요소 수명주기 후크를 의도적으로 피하기 위해 상태 개체를 직접 업데이트하는 경우 상태 개체가 아닌 데이터를 저장하는 데 간단한 변수 또는 개체를 사용해야 할 것입니다.


답변

얕은 비교는 문자열, 숫자와 같은 기본 유형의 경우 두 값이 동일한 지 확인하고 객체의 경우 참조 만 확인하여 작동합니다 . 따라서 깊은 중첩 개체를 얕게 비교하면 해당 개체 내부의 값이 아닌 참조 만 확인합니다.


답변

React에서 얕은 비교에 대한 레거시 설명 도 있습니다 .

shallowCompare는 현재 상태 및 nextState 객체뿐 아니라 현재 props 및 nextProps 객체에 대해 얕은 동등성 검사를 수행합니다.

비교되는 객체의 키를 반복하고 각 객체의 키 값이 완전히 같지 않으면 true를 반환하여이를 수행합니다.

UPD : 현재 문서 는 얕은 비교에 대해 말합니다.

React 컴포넌트의 render () 함수가 동일한 props 및 state에서 동일한 결과를 렌더링하는 경우 경우에 따라 성능 향상을 위해 React.PureComponent를 사용할 수 있습니다.

React.PureComponent의 shouldComponentUpdate ()는 객체를 얕게 비교합니다. 여기에 복잡한 데이터 구조가 포함 된 경우 더 깊은 차이에 대해 거짓 음성을 생성 할 수 있습니다. 단순한 props 및 state를 기대할 때만 PureComponent를 확장하거나, 깊은 데이터 구조가 변경된 것을 알고있을 때 forceUpdate ()를 사용하십시오.

UPD2 : 저는 조정 이 얕은 비교 이해를위한 중요한 주제 라고 생각 합니다.


답변

키 가없는 경우 위의 @supi ( https://stackoverflow.com/a/51343585/800608 ) 의 얕은 등가 스 니펫이 실패합니다 . 이를 고려해야하는 구현은 다음과 같습니다.prevObjnewObj

const shallowEqual = (objA, objB) => {
  if (!objA || !objB) {
    return objA === objB
  }
  return !Boolean(
    Object
      .keys(Object.assign({}, objA, objB))
      .find((key) => objA[key] !== objB[key])
  )
}

위의 내용은 polyfill이없는 Explorer에서는 작동하지 않습니다.


답변

예제가있는 구현이 있습니다.

const isObject = value => typeof value === 'object' && value !== null;

const compareObjects = (A, B) => {
  const keysA = Object.keys(A);
  const keysB = Object.keys(B);

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

  return !keysA.some(key => !B.hasOwnProperty(key) || A[key] !== B[key]);
};

const shallowEqual = (A, B) => {
  if (A === B) {
    return true;
  }

  if ([A, B].every(Number.isNaN)) {
    return true;
  }

  if (![A, B].every(isObject)) {
    return false;
  }

  return compareObjects(A, B);
};

const a = { field: 1 };
const b = { field: 2 };
const c = { field: { field: 1 } };
const d = { field: { field: 1 } };

console.log(shallowEqual(1, 1)); // true
console.log(shallowEqual(1, 2)); // false
console.log(shallowEqual(null, null)); // true
console.log(shallowEqual(NaN, NaN)); // true
console.log(shallowEqual([], [])); // true
console.log(shallowEqual([1], [2])); // false
console.log(shallowEqual({}, {})); // true
console.log(shallowEqual({}, a)); // false
console.log(shallowEqual(a, b)); // false
console.log(shallowEqual(a, c)); // false
console.log(shallowEqual(c, d)); // false


답변