浅比较如何在react中工作
浅比较确实检查相等性。在比较标量值(数字、字符串)时,它会比较它们的值。当比较对象时,它不比较它们的属性——只比较它们的引用(例如“它们是否指向同一个对象?”)。
让我们考虑以下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
. 要使 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
而是一个字符串。如果比较松散(==),这将通过。尽管如此,这也将导致状态更新。
补充笔记:
- 进行深度比较是没有意义的,因为如果状态对象是深度嵌套的,它会显着影响性能。但是如果它不是太嵌套并且您仍然需要深入比较,请在 shouldComponentUpdate 中实现它并检查是否足够。
- 你绝对可以直接改变 state 对象,但是组件的 state 不会受到影响,因为它在 setState 方法流中 react 实现了组件更新循环钩子。如果您直接更新状态对象以故意避免组件生命周期挂钩,那么您可能应该使用简单的变量或对象来存储数据而不是状态对象。
浅比较的工作原理是在字符串、数字等原始类型的情况下检查两个值是否相等,在对象的情况下它只检查引用。因此,如果您对深度嵌套的对象进行浅比较,它只会检查引用而不是该对象内的值。
React 中也有对浅比较的遗留解释:
ShallowCompare 对当前 props 和 nextProps 对象以及当前 state 和 nextState 对象执行浅层相等性检查。
它通过迭代要比较的对象的键并在每个对象中的键的值不严格相等时返回 true 来做到这一点。
UPD:当前文档说明了浅比较:
如果你的 React 组件的 render() 函数在给定相同的 props 和 state 的情况下呈现相同的结果,你可以在某些情况下使用 React.PureComponent 来提高性能。
React.PureComponent 的 shouldComponentUpdate() 只是浅层比较对象。如果这些包含复杂的数据结构,则可能会对更深层次的差异产生假阴性。仅在您希望拥有简单的 props 和 state 时才扩展 PureComponent,或者在您知道深层数据结构已更改时使用 forceUpdate()
UPD2:我认为和解也是浅比较理解的重要主题。
如果有一个没有的键,上面@supi ( https://stackoverflow.com/a/51343585/800608 )的浅等片段将失败。这是一个应该考虑到这一点的实现:prevObj
newObj
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 的资源管理器中不起作用。