mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-06-07 12:15:06 +00:00
[change] call 'onLayout' when elements are resized
Uses ResizeObserver to monitor layout changes. Falls back to window.onresize (with initial firing). Fix #60 Close #848
This commit is contained in:
committed by
Nicolas Gallagher
parent
9427eea293
commit
5a04d07a35
+65
-14
@@ -9,6 +9,7 @@
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import debounce from 'debounce';
|
||||
import findNodeHandle from '../../exports/findNodeHandle';
|
||||
|
||||
const emptyObject = {};
|
||||
const registry = {};
|
||||
@@ -16,22 +17,68 @@ const registry = {};
|
||||
let id = 1;
|
||||
const guid = () => `r-${id++}`;
|
||||
|
||||
let resizeObserver;
|
||||
if (canUseDOM) {
|
||||
const triggerAll = () => {
|
||||
Object.keys(registry).forEach(key => {
|
||||
const instance = registry[key];
|
||||
instance._handleLayout();
|
||||
if (typeof window.ResizeObserver !== 'undefined') {
|
||||
resizeObserver = new window.ResizeObserver(entries => {
|
||||
entries.forEach(({ target }) => {
|
||||
const instance = registry[target._onLayoutId];
|
||||
instance && instance._handleLayout();
|
||||
});
|
||||
});
|
||||
};
|
||||
} else {
|
||||
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
|
||||
console.warn(
|
||||
'onLayout relies on ResizeObserver which is not supported by your browser. ' +
|
||||
'Please include a polyfill, e.g., https://github.com/que-etc/resize-observer-polyfill. ' +
|
||||
'Falling back to window.onresize.'
|
||||
);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', debounce(triggerAll, 16), false);
|
||||
const triggerAll = () => {
|
||||
Object.keys(registry).forEach(key => {
|
||||
const instance = registry[key];
|
||||
instance._handleLayout();
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('resize', debounce(triggerAll, 16), false);
|
||||
}
|
||||
}
|
||||
|
||||
const observe = instance => {
|
||||
const id = guid();
|
||||
registry[id] = instance;
|
||||
|
||||
if (resizeObserver) {
|
||||
const node = findNodeHandle(instance);
|
||||
node._onLayoutId = id;
|
||||
resizeObserver.observe(node);
|
||||
} else {
|
||||
const id = guid();
|
||||
instance._onLayoutId = id;
|
||||
instance._handleLayout();
|
||||
}
|
||||
};
|
||||
|
||||
const unobserve = instance => {
|
||||
delete registry[instance._onLayoutId];
|
||||
if (resizeObserver) {
|
||||
const node = findNodeHandle(instance);
|
||||
delete node._onLayoutId;
|
||||
resizeObserver.unobserve(node);
|
||||
} else {
|
||||
delete instance._onLayoutId;
|
||||
}
|
||||
};
|
||||
|
||||
const safeOverride = (original, next) => {
|
||||
if (original) {
|
||||
return function prototypeOverride() {
|
||||
original.call(this);
|
||||
next.call(this);
|
||||
/* eslint-disable prefer-rest-params */
|
||||
original.call(this, arguments);
|
||||
next.call(this, arguments);
|
||||
/* eslint-enable prefer-rest-params */
|
||||
};
|
||||
}
|
||||
return next;
|
||||
@@ -47,16 +94,20 @@ const applyLayout = Component => {
|
||||
function componentDidMount() {
|
||||
this._layoutState = emptyObject;
|
||||
this._isMounted = true;
|
||||
this._onLayoutId = guid();
|
||||
registry[this._onLayoutId] = this;
|
||||
this._handleLayout();
|
||||
observe(this);
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentDidUpdate = safeOverride(
|
||||
componentDidUpdate,
|
||||
function componentDidUpdate() {
|
||||
this._handleLayout();
|
||||
function componentDidUpdate(prevProps) {
|
||||
if (this.props.onLayout && !prevProps.onLayout) {
|
||||
observe(this);
|
||||
} else if (!this.props.onLayout && prevProps.onLayout) {
|
||||
unobserve(this);
|
||||
} else if (!resizeObserver) {
|
||||
this._handleLayout();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -64,7 +115,7 @@ const applyLayout = Component => {
|
||||
componentWillUnmount,
|
||||
function componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
delete registry[this._onLayoutId];
|
||||
unobserve(this);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user