mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-08-15 18:45:06 +00:00
[change] Add useElementLayout hook to implement onLayout callback
A hook equivalent for implementing onLayout in function components. Removes the fallback to using window resize events. A ResizeObserver polyfill is now requires to use the `onLayout` prop.
This commit is contained in:
@@ -45,6 +45,7 @@
|
||||
"ReactPropsChainableTypeChecker": false,
|
||||
"ReactPropsCheckType": false,
|
||||
"ReactPropTypes": false,
|
||||
"ResizeObserver": false,
|
||||
"SyntheticEvent": false
|
||||
},
|
||||
"rules": {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type { ElementRef } from 'react';
|
||||
import type { LayoutEvent } from '../types';
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import useLayoutEffect from './useLayoutEffect';
|
||||
import UIManager from '../exports/UIManager';
|
||||
|
||||
const DOM_LAYOUT_HANDLER_NAME = '__reactLayoutHandler';
|
||||
|
||||
let didWarn = false;
|
||||
let resizeObserver = null;
|
||||
|
||||
function getResizeObserver(): ?ResizeObserver {
|
||||
if (canUseDOM && typeof window.ResizeObserver !== 'undefined') {
|
||||
if (resizeObserver == null) {
|
||||
resizeObserver = new window.ResizeObserver(function(entries) {
|
||||
entries.forEach(entry => {
|
||||
const node = entry.target;
|
||||
const onLayout = node[DOM_LAYOUT_HANDLER_NAME];
|
||||
if (typeof onLayout === 'function') {
|
||||
// We still need to measure the view because browsers don't yet provide
|
||||
// border-box dimensions in the entry
|
||||
UIManager.measure(node, (x, y, width, height, left, top) => {
|
||||
const event: LayoutEvent = {
|
||||
// $FlowFixMe
|
||||
nativeEvent: {
|
||||
layout: { x, y, width, height, left, top }
|
||||
},
|
||||
timeStamp: Date.now()
|
||||
};
|
||||
Object.defineProperty(event.nativeEvent, 'target', {
|
||||
enumerable: true,
|
||||
get: () => entry.target
|
||||
});
|
||||
onLayout(event);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if (!didWarn) {
|
||||
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.'
|
||||
);
|
||||
didWarn = true;
|
||||
}
|
||||
}
|
||||
return resizeObserver;
|
||||
}
|
||||
|
||||
export default function useElementLayout(
|
||||
ref: ElementRef<any>,
|
||||
onLayout?: (e: LayoutEvent) => void
|
||||
) {
|
||||
const observer = getResizeObserver();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const node = ref.current;
|
||||
if (node != null && observer != null && typeof onLayout === 'function') {
|
||||
observer.observe(node);
|
||||
// $FlowFixMe
|
||||
node[DOM_LAYOUT_HANDLER_NAME] = onLayout;
|
||||
}
|
||||
return () => {
|
||||
if (node != null && observer != null) {
|
||||
observer.unobserve(node);
|
||||
// $FlowFixMe
|
||||
delete node[DOM_LAYOUT_HANDLER_NAME];
|
||||
}
|
||||
};
|
||||
}, [ref, onLayout, observer]);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* useLayoutEffect throws an error on the server. On the few occasions where is
|
||||
* problematic, use this hook.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import { useEffect, useLayoutEffect } from 'react';
|
||||
|
||||
const useLayoutEffectImpl: typeof useLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
|
||||
|
||||
export default useLayoutEffectImpl;
|
||||
+4
-2
@@ -35,8 +35,10 @@ export type LayoutValue = {
|
||||
|
||||
export type LayoutEvent = {
|
||||
nativeEvent: {
|
||||
layout: LayoutValue
|
||||
}
|
||||
layout: LayoutValue,
|
||||
target: any
|
||||
},
|
||||
timeStamp: number
|
||||
};
|
||||
|
||||
export type PointValue = {|
|
||||
|
||||
Reference in New Issue
Block a user