mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-23 06:48:35 +00:00
[change] onLayout improvements
1. Fires when window resizes 2. Guards against nodes being unmounted Fix #397 Ref #60
This commit is contained in:
@@ -25,7 +25,6 @@
|
||||
"dependencies": {
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"asap": "^2.0.5",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"debounce": "^1.0.0",
|
||||
"deep-assign": "^2.0.0",
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import debounce from 'debounce';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
const win = ExecutionEnvironment.canUseDOM ? window : { screen: {} };
|
||||
const win = canUseDOM ? window : { screen: {} };
|
||||
|
||||
const dimensions = {};
|
||||
|
||||
@@ -38,6 +38,9 @@ class Dimensions {
|
||||
}
|
||||
|
||||
Dimensions.set();
|
||||
ExecutionEnvironment.canUseDOM && window.addEventListener('resize', debounce(Dimensions.set, 50));
|
||||
|
||||
if (canUseDOM) {
|
||||
window.addEventListener('resize', debounce(Dimensions.set, 16), false);
|
||||
}
|
||||
|
||||
module.exports = Dimensions;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import asap from 'asap';
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import generateCss from './generateCss';
|
||||
import hash from './hash';
|
||||
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
|
||||
import staticCss from './staticCss';
|
||||
|
||||
const emptyObject = {};
|
||||
@@ -111,7 +111,7 @@ class StyleManager {
|
||||
className = createClassName(prop, value);
|
||||
this._addToCache(className, prop, value);
|
||||
if (canUseDOM) {
|
||||
asap(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const sheet = this.mainSheet.sheet;
|
||||
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
||||
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
||||
|
||||
+17
-12
@@ -1,5 +1,5 @@
|
||||
import asap from 'asap';
|
||||
import CSSPropertyOperations from 'react-dom/lib/CSSPropertyOperations';
|
||||
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
|
||||
|
||||
const getRect = node => {
|
||||
const height = node.offsetHeight;
|
||||
@@ -15,13 +15,15 @@ const getRect = node => {
|
||||
};
|
||||
|
||||
const measureLayout = (node, relativeToNativeNode, callback) => {
|
||||
asap(() => {
|
||||
const relativeNode = relativeToNativeNode || node.parentNode;
|
||||
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);
|
||||
requestAnimationFrame(() => {
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -43,13 +45,16 @@ const UIManager = {
|
||||
},
|
||||
|
||||
measureInWindow(node, callback) {
|
||||
const { height, left, top, width } = getRect(node);
|
||||
callback(left, top, width, height);
|
||||
requestAnimationFrame(() => {
|
||||
if (node) {
|
||||
const { height, left, top, width } = getRect(node);
|
||||
callback(left, top, width, height);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
measureLayout(node, relativeToNativeNode, onFail, onSuccess) {
|
||||
const relativeTo = relativeToNativeNode || node.parentNode;
|
||||
measureLayout(node, relativeTo, onSuccess);
|
||||
measureLayout(node, relativeToNativeNode, onSuccess);
|
||||
},
|
||||
|
||||
updateView(node, props, component /* only needed to surpress React errors in development */) {
|
||||
|
||||
@@ -5,24 +5,66 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import emptyFunction from 'fbjs/lib/emptyFunction';
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import debounce from 'debounce';
|
||||
|
||||
const emptyObject = {};
|
||||
const registry = {};
|
||||
|
||||
let id = 1;
|
||||
const guid = () => `r-${id++}`;
|
||||
|
||||
if (canUseDOM) {
|
||||
const triggerAll = () => {
|
||||
Object.keys(registry).forEach(key => {
|
||||
const instance = registry[key];
|
||||
instance._handleLayout();
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('resize', debounce(triggerAll, 16), false);
|
||||
}
|
||||
|
||||
const safeOverride = (original, next) => {
|
||||
if (original) {
|
||||
return function prototypeOverride() {
|
||||
original.call(this);
|
||||
next.call(this);
|
||||
};
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
const applyLayout = Component => {
|
||||
const componentDidMount = Component.prototype.componentDidMount || emptyFunction;
|
||||
const componentDidUpdate = Component.prototype.componentDidUpdate || emptyFunction;
|
||||
const componentDidMount = Component.prototype.componentDidMount;
|
||||
const componentDidUpdate = Component.prototype.componentDidUpdate;
|
||||
const componentWillUnmount = Component.prototype.componentWillUnmount;
|
||||
|
||||
Component.prototype.componentDidMount = function() {
|
||||
componentDidMount.call(this);
|
||||
this._layoutState = emptyObject;
|
||||
this._handleLayout();
|
||||
};
|
||||
Component.prototype.componentDidMount = safeOverride(
|
||||
componentDidMount,
|
||||
function componentDidMount() {
|
||||
this._layoutState = emptyObject;
|
||||
this._isMounted = true;
|
||||
this._onLayoutId = guid();
|
||||
registry[this._onLayoutId] = this;
|
||||
this._handleLayout();
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentDidUpdate = function() {
|
||||
componentDidUpdate.call(this);
|
||||
this._handleLayout();
|
||||
};
|
||||
Component.prototype.componentDidUpdate = safeOverride(
|
||||
componentDidUpdate,
|
||||
function componentDidUpdate() {
|
||||
this._handleLayout();
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentWillUnmount = safeOverride(
|
||||
componentWillUnmount,
|
||||
function componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
delete registry[this._onLayoutId];
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype._handleLayout = function() {
|
||||
const layout = this._layoutState;
|
||||
@@ -30,13 +72,14 @@ const applyLayout = Component => {
|
||||
|
||||
if (onLayout) {
|
||||
this.measure((x, y, width, height) => {
|
||||
if (!this._isMounted) return;
|
||||
|
||||
if (
|
||||
layout.x !== x || layout.y !== y || layout.width !== width || layout.height !== height
|
||||
) {
|
||||
const nextLayout = { x, y, width, height };
|
||||
const nativeEvent = { layout: nextLayout };
|
||||
this._layoutState = { x, y, width, height };
|
||||
const nativeEvent = { layout: this._layoutState };
|
||||
onLayout({ nativeEvent, timeStamp: Date.now() });
|
||||
this._layoutState = nextLayout;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ arrify@^1.0.0, arrify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||
|
||||
asap@^2.0.5, asap@~2.0.3:
|
||||
asap@~2.0.3:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user