场景:父节点触发了更新,但是在子节点中只有部分(图中是绿色) 是真正需要更行并渲染, 其他的不需要。
理想情况下是只渲染必要的节点,React 默认是从最顶的绿色节点开始以下的所有子节点会被渲染。
可以参考 reactjs.org - Optimizing Performance 使用 shouldComponentUpdate
或者 PureComponent
进行优化。
如果组件继承了 Component
, 则可以通过 shouldComponentUpdate
方法处理不必要的渲染,返回 false
则不调用 render
方法, 否则反之。 默认返回 true
。
如果组件继承了 PureComponent
, 我们就不用写 shouldComponentUpdate
来处理了, 但是 PureComponent
只进行浅表比较。
使用 shouldComponentUpdate
的时候需要确保:
- shouldComponentUpdate 检查够快
- shouldComponentUpdate 检查够简单
对象的比较
对象的属性如果修改了, 但是对象还是原来的对象, 那么判等 ===
结果是 true。如果单纯使用 ===
会导致需要调用 render
的时候也没有调用 render
。
如果使用 const newValue2 = Object.assign({}, oldValue);
, 不论对象是否改变, 通过判等(===
)结果都是 false。 可以解决 浅表对比导致误判,但是解决不了冗余处理的问题。
如果是对于对象里面的属性进行深层的对比:
const isObjectEqual = (obj1, obj2) => {
if(!isObject(obj1) || !isObject(obj2)) {
return false;
}
// are the references the same?
if (obj1 === obj2) {
return true;
}
// does it contain objects with the same keys?
const item1Keys = Object.keys(obj1).sort();
const item2Keys = Object.keys(obj2).sort();
if (!isArrayEqual(item1Keys, item2Keys)) {
return false;
}
// does every object in props have the same reference?
return item2Keys.every(key => {
const value = obj1[key];
const nextValue = obj2[key];
if (value === nextValue) {
return true;
}
// special case for arrays - check one level deep
return Array.isArray(value) &&
Array.isArray(nextValue) &&
isArrayEqual(value, nextValue);
});
};
const isArrayEqual = (array1 = [], array2 = []) => {
if (array1 === array2) {
return true;
}
// check one level deep
return array1.length === array2.length &&
array1.every((item, index) => item === array2[index]);
};
可以使用一些工具帮助我们找到有性能问题的地方:
- console.time
- React.perf
- 浏览器工具: Firefox, Chrome
例如:
export default store => next => action => {
console.time(action.type);
// `next` is a function that takes an 'action' and sends it through to the 'reducers'
// this will result in a re-render of your application
const result = next(action);
// how long did the render take?
console.timeEnd(action.type);
return result;
};
import Perf from 'react-addons-perf';
export default store => next => action => {
const key = `performance:${action.type}`;
Perf.start();
// will re-render the application with new state
const result = next(action);
Perf.stop();
console.group(key);
console.info('wasted');
Perf.printWasted();
// any other Perf measurements you are interested in
console.groupEnd(key);
return result;
};
规范化状态 和 非规范化状态, 尽量使用规范化状态。
函数调用缓存库 memoization library - alexreardon/memoize-one
列表拖放库 Beautiful and accessible drag and drop for lists with React - atlassian/react-beautiful-dnd
参考文档:
- Performance optimisations for React applications
- Performance optimisations for React applications: Round 2
- reactjs.org - Optimizing Performance
- reactjs.org - Performance Tools
只是部分笔记, 详细的请查阅参考文档