浅比较如何在react中工作

IT技术 javascript reactjs
2021-01-12 08:18:29

这个React文档中,据说

ShallowCompare 对当前 props 和 nextProps 对象以及当前 state 和 nextState 对象执行浅层相等性检查。

我无法理解的是,如果它对对象进行浅层比较,则 shouldComponentUpdate 方法将始终返回 true,如

我们不应该改变状态。

如果我们不改变状态,那么比较将始终返回 false,因此 shouldComponent 更新将始终返回 true。我对它是如何工作的以及我们将如何覆盖它以提高性能感到困惑。

6个回答

浅比较确实检查相等性。在比较标量值(数字、字符串)时,它会比较它们的值。当比较对象时,它不比较它们的属性——只比较它们的引用(例如“它们是否指向同一个对象?”)。

让我们考虑以下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);

浅比较是检测变化的有效方法。它希望您不会改变数据。

2021-03-20 08:18:29
@sunquan 你能写一个答案吗?
2021-03-20 08:18:29
这个答案描述了 JS 中相等 (==) 和严格相等 (===) 运算符之间的区别。问题是关于浅层比较,在 React 中是通过检查两个对象的所有 props 之间的相等性来实现的。
2021-04-05 08:18:29
@AjayGaur 虽然这个答案可以帮助您理解 JavaScript 中的严格相等 (===),但它并没有告诉您有关 React 中的shallowCompare() 函数的任何信息(我猜回答者误解了您的问题)。ShallowCompare() 所做的实际上是在您提供的文档中:迭代正在比较的对象的键,并在每个对象中的键的值不严格相等时返回 true。如果你仍然不理解这个函数以及为什么你不应该改变状态,我可以为你写一个答案。
2021-04-09 08:18:29
因此,如果我们正在编写代码,那么如果我们有标量值,那么我们是否应该改变它们,因为如果我们克隆它们,相等性检查将返回 false?
2021-04-11 08:18:29

浅比较是指被比较的对象的属性是使用“===”或严格相等来完成的,并且不会对属性进行更深入的比较。例如

// 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. 要使 2 个对象相同,它们应该指向同一个对象。因此,这导致被评估的状态被更新

// 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.

这次每个属性都返回真以进行严格比较,因为新旧对象中的团队属性指向同一个对象。

// 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. 你绝对可以直接改变 state 对象,但是组件的 state 不会受到影响,因为它在 setState 方法流中 react 实现了组件更新循环钩子。如果您直接更新状态对象以故意避免组件生命周期挂钩,那么您可能应该使用简单的变量或对象来存储数据而不是状态对象。
@javascripting - 这就是为什么你会在对象改变时克隆(例如使用 Object.assign())而不是改变它们,这样 React 就会知道引用何时改变以及组件何时需要更新。
2021-03-15 08:18:29
数组呢?
2021-03-18 08:18:29
如果prevObj包含没有的键newObj,则比较将失败。
2021-03-26 08:18:29
@mzedeler - 它不会因为“for in”在 newObj 上迭代而不是在 prevObj 上迭代。尝试在浏览器开发者控制台中按原样运行代码。另外请不要把这个浅比较的实现看得太重,这只是为了演示这个概念
2021-03-29 08:18:29
这是否意味着如果我通过 props 传递一个对象或将状态与下一个状态进行比较,该组件将永远不会重新渲染,因为即使该对象的属性已更改,它仍将指向同一个对象,从而导致假,因此,不重新渲染?
2021-04-03 08:18:29

浅比较的工作原理是在字符串、数字等原始类型的情况下检查两个值是否相等在对象的情况下它只检查引用因此,如果您对深度嵌套的对象进行浅比较,它只会检查引用而不是该对象内的值。

React 中也有对浅比较的遗留解释

ShallowCompare 对当前 props 和 nextProps 对象以及当前 state 和 nextState 对象执行浅层相等性检查。

它通过迭代要比较的对象的键并在每个对象中的键的值不严格相等时返回 true 来做到这一点。

UPD当前文档说明了浅比较:

如果你的 React 组件的 render() 函数在给定相同的 props 和 state 的情况下呈现相同的结果,你可以在某些情况下使用 React.PureComponent 来提高性能。

React.PureComponent 的 shouldComponentUpdate() 只是浅层比较对象。如果这些包含复杂的数据结构,则可能会对更深层次的差异产生假阴性。仅在您希望拥有简单的 props 和 state 时才扩展 PureComponent,或者在您知道深层数据结构已更改时使用 forceUpdate()

UPD2:我认为和解也是浅比较理解的重要主题。

不应该是“假的” and returning true when the values
2021-03-21 08:18:29

如果有一个没有的键,上面@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 的资源管理器中不起作用。

看起来不错,但在这种情况下,传递两个 NaN 返回 false 而在之前的答案中它是 true。
2021-03-28 08:18:29