From b4e3427fea9bd943e3b3be13def0f4ffb3df917c Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Wed, 23 May 2018 11:04:47 -0700 Subject: [PATCH] [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. --- .../src/exports/UIManager/index.js | 18 ++++++---- .../src/modules/applyLayout/index.js | 36 +++++++++---------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/packages/react-native-web/src/exports/UIManager/index.js b/packages/react-native-web/src/exports/UIManager/index.js index 8e8ed6fa..7ed29831 100644 --- a/packages/react-native-web/src/exports/UIManager/index.js +++ b/packages/react-native-web/src/exports/UIManager/index.js @@ -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); } }, diff --git a/packages/react-native-web/src/modules/applyLayout/index.js b/packages/react-native-web/src/modules/applyLayout/index.js index a57be60f..869f6011 100644 --- a/packages/react-native-web/src/modules/applyLayout/index.js +++ b/packages/react-native-web/src/modules/applyLayout/index.js @@ -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() }); + } } }); }