我正在通过减少不必要的重新渲染来优化React应用的性能。我正在处理的组件会收到一个包含一个对象的道具,该对象带有许多键,包括对象数组。我正在使用shouldComponentUpdate
检查道具的更改,但无法正常工作:
shouldComponentUpdate(nextProps) {
if (!(_.isEqual(nextProps, this.props))) {
console.log('difference', _.differenceWith(nextProps, this.props));
return true;
}
return false;
}
isEqual
是Lodash的一种用于深度比较对象的方法。 differenceWith
是一种Lodash方法,用于发现两个对象之间的差异。奇怪的是,使用isEqual
不会减少重新渲染,并且differenceWith
打印一个空数组[]
。但是,如果我使用JSON.stringify
而不是isEqual
,则重新渲染减少了一半,但是differenceWith
仍然打印[]
。
shouldComponentUpdate(nextProps) {
if ( JSON.stringify(nextProps) !== JSON.stringify(this.props) ) {
console.log('difference', _.differenceWith(nextProps, this.props));
return true;
}
return false;
}
为什么isEqual
和JSON.stringify
在本质上做相同的事情时,尽管行为方式不同(请注意isEqual
也是顺序敏感的),为什么会有区别?
在这里避免重新渲染的最佳方法是什么?
答案 0 :(得分:2)
1-为什么isEqual和JSON.stringify在本质上做相同的事情时,尽管行为方式不同(请注意isEqual也是顺序敏感的),为什么会有区别?
看看我发现的here。
这取决于。对于JSON.stringify(),顺序很重要。因此,如果键值对在两个对象中的顺序不同,但相同,则它将返回false。尽管在Lodash isEqual中无关紧要,但它会在键值对存在的情况下返回true。
const one = { fruit: '', energy: '255kJ', }; const two = { energy: '255kJ', fruit: '', }; // Using JavaScript JSON.stringify(one) === JSON.stringify(two); // false // Using Lodash _.isEqual(one, two); // true
这意味着您JSON.stringify
可以工作,但并非在所有情况下都可以工作,因此可能不应该在您的情况下使用它。
我还发现了一个benchmark,可以将两者进行比较。 JSON.stringify
对于深度较浅的嵌套对象更好,但是_.isEqual
对于深度较深的嵌套对象更好。
_.differenceWith用于比较接收到3个参数的数组,其中2个是要比较的数组,第三个是比较器。
这样做_.differenceWith(nextProps, this.props)
与_.difference(nextProps, this.props)
一样,如您在文档中看到的
_。differenceWith
此方法类似于_.difference,不同之处在于它接受比较器,该比较器被调用以将数组的元素与值进行比较。结果值的顺序和参考由第一个数组确定。比较器由两个参数调用:(arrVal,othVal)。
_。difference
使用SameValueZero进行相等比较,创建其他给定数组中未包含的数组值的数组。结果值的顺序和引用由第一个数组确定。
因此使用其中之一,将返回一个具有不同值的新数组。如果返回[]
,则表示该数组具有相同的值,但可以位于其他值中。
_.differenceWith
很好。可以在文档示例中看到。
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); // => [{ 'x': 2, 'y': 1 }]
2-避免在此处重新渲染的最佳方法是什么?
对于您的情况,我建议使用_.isEqual
,因为它可以精确比较数组的顺序,并且您可以拥有具有相同属性但顺序不同的对象,并且它们将是相同的。
使用所说的
奇怪的是,使用isEqual不会减少重新渲染,而differenceWith打印一个空数组[]。但是,如果我使用JSON.stringify而不是isEqual,则重新渲染将减少一半...
我不确定为什么会这样,它取决于很多事情,但是如果您想比较组件的状态或属性,则绝对应该使用_.isEqual
。
您也可以React.memo
和React.PureComponent
,这在某些情况下可能会有所帮助。
正如您在memo
文档中所见
如果给定相同的道具,功能组件呈现相同的结果,则可以将其包装在对React.memo的调用中,以在某些情况下通过记忆结果来提高性能。这意味着React将跳过渲染组件,并重用最后渲染的结果。 ... 此方法仅作为性能优化存在。不要依靠它来“阻止”渲染,因为这可能会导致错误
还有PureComponent
React.PureComponent与React.Component类似。它们之间的区别在于React.Component并未实现shouldComponentUpdate(),但是React.PureComponent却通过浅层的prop和状态比较来实现它。
如果您的React组件的render()函数在相同的道具和状态下呈现相同的结果,则在某些情况下,您可以使用React.PureComponent来提高性能。