[fix] UIManager measurements don't block

A large number of layout measurements (and their corresponding tasks)
can block the main thread. Make the work async and try to keep the UI
responsive to user input while the layout work is taking place.
This commit is contained in:
Nicolas Gallagher
2018-05-23 11:04:47 -07:00
parent a82cfbe504
commit b4e3427fea
2 changed files with 29 additions and 25 deletions

View File

@@ -27,11 +27,13 @@ const getRect = node => {
const measureLayout = (node, relativeToNativeNode, callback) => {
const relativeNode = relativeToNativeNode || (node && node.parentNode);
if (node && relativeNode) {
const relativeRect = getRect(relativeNode);
const { height, left, top, width } = getRect(node);
const x = left - relativeRect.left;
const y = top - relativeRect.top;
callback(x, y, width, height, left, top);
setTimeout(() => {
const relativeRect = getRect(relativeNode);
const { height, left, top, width } = getRect(node);
const x = left - relativeRect.left;
const y = top - relativeRect.top;
callback(x, y, width, height, left, top);
}, 0);
}
};
@@ -54,8 +56,10 @@ const UIManager = {
measureInWindow(node, callback) {
if (node) {
const { height, left, top, width } = getRect(node);
callback(left, top, width, height);
setTimeout(() => {
const { height, left, top, width } = getRect(node);
callback(left, top, width, height);
}, 0);
}
},

View File

@@ -56,9 +56,7 @@ const observe = instance => {
resizeObserver.observe(node);
} else {
instance._layoutId = id;
setTimeout(() => {
instance._handleLayout();
}, 0);
instance._handleLayout();
}
};
@@ -122,22 +120,24 @@ const applyLayout = Component => {
const layout = this._layoutState;
const { onLayout } = this.props;
if (this._isMounted && onLayout) {
if (onLayout) {
this.measure((x, y, width, height) => {
if (
layout.x !== x ||
layout.y !== y ||
layout.width !== width ||
layout.height !== height
) {
this._layoutState = { x, y, width, height };
const nativeEvent = {
layout: this._layoutState,
get target() {
return findNodeHandle(this);
}
};
onLayout({ nativeEvent, timeStamp: Date.now() });
if (this._isMounted) {
if (
layout.x !== x ||
layout.y !== y ||
layout.width !== width ||
layout.height !== height
) {
this._layoutState = { x, y, width, height };
const nativeEvent = {
layout: this._layoutState,
get target() {
return findNodeHandle(this);
}
};
onLayout({ nativeEvent, timeStamp: Date.now() });
}
}
});
}