code

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

codestyles 2020. 11. 1. 18:09
반응형

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


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

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

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

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

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


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

다음 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.teamsupdated_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. Doing deep compare is pointless as it would significantly effect performance if the state object is deeply nested. But if its not too nested and you still need a deep compare, implement it in shouldComponentUpdate and check if that suffices.
  2. You can definitely mutate the state object directly but the state of the components would not be affected, since its in the setState method flow that react implements the component update cycle hooks. If you update the state object directly to deliberately avoid the component life-cycle hooks, then probably you should be using a simple variable or object to store the data and not the state object.

Shallow compare works by checking if two values are equal in case of primitive types like string, numbers and in case of object it just checks the reference. So if you shallow compare a deep nested object it will just check the reference not the values inside that object.


There is also legacy explanation of shallow compare in React:

shallowCompare performs a shallow equality check on the current props and nextProps objects as well as the current state and nextState objects.

It does this by iterating on the keys of the objects being compared and returning true when the values of a key in each object are not strictly equal.

UPD: Current documentation says about shallow compare:

If your React component's render() function renders the same result given the same props and state, you can use React.PureComponent for a performance boost in some cases.

React.PureComponent's shouldComponentUpdate() only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only extend PureComponent when you expect to have simple props and state, or use forceUpdate() when you know deep data structures have changed

UPD2: I think Reconciliation is also important theme for shallow compare understanding.


The shallow equal snippet by @supi above (https://stackoverflow.com/a/51343585/800608) fails if prevObj has a key that newObj doesn't have. Here is an implementation that should take that into account:

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

Note that the above doesn't work in Explorer without polyfills.

참고URL : https://stackoverflow.com/questions/36084515/how-does-shallow-compare-work-in-react

반응형