[add] useWindowDimensions hook

Add the 'useWindowDimensions' hook from React Native

Close #1487
This commit is contained in:
Maxime Thirouin
2019-11-19 23:31:59 +01:00
committed by Nicolas Gallagher
parent 4763cc71c6
commit df1b62cd45
5 changed files with 77 additions and 12 deletions
@@ -64,5 +64,6 @@ module.exports = {
findNodeHandle: true,
processColor: true,
render: true,
unmountComponentAtNode: true
unmountComponentAtNode: true,
useWindowDimensions: true
};
+4 -2
View File
@@ -7,12 +7,14 @@
* @flow
*/
import type { DisplayMetrics } from '../Dimensions';
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import Dimensions from '../Dimensions';
const DeviceInfo = {
Dimensions: {
get windowPhysicalPixels() {
get windowPhysicalPixels(): DisplayMetrics {
const { width, height, fontScale, scale } = Dimensions.get('window');
return {
width: width * scale,
@@ -21,7 +23,7 @@ const DeviceInfo = {
fontScale
};
},
get screenPhysicalPixels() {
get screenPhysicalPixels(): DisplayMetrics {
const { width, height, fontScale, scale } = Dimensions.get('screen');
return {
width: width * scale,
+30 -8
View File
@@ -12,15 +12,31 @@ import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import debounce from 'debounce';
import invariant from 'fbjs/lib/invariant';
export type DisplayMetrics = {|
fontScale: number,
height: number,
scale: number,
width: number
|};
type DimensionsValue = {|
window?: DisplayMetrics,
screen?: DisplayMetrics
|};
type DimensionKey = 'window' | 'screen';
type DimensionEventListenerType = 'change';
const win = canUseDOM
? window
: {
devicePixelRatio: undefined,
innerHeight: undefined,
innerWidth: undefined,
innerHeight: (undefined: any),
innerWidth: (undefined: any),
screen: {
height: undefined,
width: undefined
height: (undefined: any),
width: (undefined: any)
}
};
@@ -28,12 +44,12 @@ const dimensions = {};
const listeners = {};
export default class Dimensions {
static get(dimension: string): Object {
static get(dimension: DimensionKey): DisplayMetrics {
invariant(dimensions[dimension], `No dimension set for key ${dimension}`);
return dimensions[dimension];
}
static set(initialDimensions: ?{ [key: string]: any }): void {
static set(initialDimensions: ?DimensionsValue): void {
if (initialDimensions) {
if (canUseDOM) {
invariant(false, 'Dimensions cannot be set in the browser');
@@ -64,12 +80,18 @@ export default class Dimensions {
}
}
static addEventListener(type: string, handler: Function): void {
static addEventListener(
type: DimensionEventListenerType,
handler: DimensionsValue => void
): void {
listeners[type] = listeners[type] || [];
listeners[type].push(handler);
}
static removeEventListener(type: string, handler: Function): void {
static removeEventListener(
type: DimensionEventListenerType,
handler: DimensionsValue => void
): void {
if (Array.isArray(listeners[type])) {
listeners[type] = listeners[type].filter(_handler => _handler !== handler);
}
@@ -0,0 +1,35 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
'use strict';
import type { DisplayMetrics } from '../Dimensions';
import Dimensions from '../Dimensions';
import { useEffect, useState } from 'react';
export default function useWindowDimensions(): DisplayMetrics {
const [dims, setDims] = useState(() => Dimensions.get('window'));
useEffect(() => {
function handleChange({ window }) {
// $FlowFixMe
setDims(window);
}
Dimensions.addEventListener('change', handleChange);
// We might have missed an update between calling `get` in render and
// `addEventListener` in this handler, so we set it here. If there was
// no change, React will filter out this update as a no-op.
setDims(Dimensions.get('window'));
return () => {
Dimensions.removeEventListener('change', handleChange);
};
}, []);
return dims;
}
+6 -1
View File
@@ -73,6 +73,9 @@ import TVEventHandler from './exports/TVEventHandler';
// plugins
import DeviceEventEmitter from './exports/DeviceEventEmitter';
// hooks
import useWindowDimensions from './exports/useWindowDimensions';
export {
// top-level API
createElement as unstable_createElement,
@@ -145,5 +148,7 @@ export {
TimePickerAndroid,
TVEventHandler,
// plugins
DeviceEventEmitter
DeviceEventEmitter,
// hooks
useWindowDimensions
};