Skip to content

Commit df1b62c

Browse files
MoOxnecolas
authored andcommitted
[add] useWindowDimensions hook
Add the 'useWindowDimensions' hook from React Native Close #1487
1 parent 4763cc7 commit df1b62c

File tree

5 files changed

+77
-12
lines changed

5 files changed

+77
-12
lines changed

packages/babel-plugin-react-native-web/src/moduleMap.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,6 @@ module.exports = {
6464
findNodeHandle: true,
6565
processColor: true,
6666
render: true,
67-
unmountComponentAtNode: true
67+
unmountComponentAtNode: true,
68+
useWindowDimensions: true
6869
};

packages/react-native-web/src/exports/DeviceInfo/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
* @flow
88
*/
99

10+
import type { DisplayMetrics } from '../Dimensions';
11+
1012
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
1113
import Dimensions from '../Dimensions';
1214

1315
const DeviceInfo = {
1416
Dimensions: {
15-
get windowPhysicalPixels() {
17+
get windowPhysicalPixels(): DisplayMetrics {
1618
const { width, height, fontScale, scale } = Dimensions.get('window');
1719
return {
1820
width: width * scale,
@@ -21,7 +23,7 @@ const DeviceInfo = {
2123
fontScale
2224
};
2325
},
24-
get screenPhysicalPixels() {
26+
get screenPhysicalPixels(): DisplayMetrics {
2527
const { width, height, fontScale, scale } = Dimensions.get('screen');
2628
return {
2729
width: width * scale,

packages/react-native-web/src/exports/Dimensions/index.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,44 @@ import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
1212
import debounce from 'debounce';
1313
import invariant from 'fbjs/lib/invariant';
1414

15+
export type DisplayMetrics = {|
16+
fontScale: number,
17+
height: number,
18+
scale: number,
19+
width: number
20+
|};
21+
22+
type DimensionsValue = {|
23+
window?: DisplayMetrics,
24+
screen?: DisplayMetrics
25+
|};
26+
27+
type DimensionKey = 'window' | 'screen';
28+
29+
type DimensionEventListenerType = 'change';
30+
1531
const win = canUseDOM
1632
? window
1733
: {
1834
devicePixelRatio: undefined,
19-
innerHeight: undefined,
20-
innerWidth: undefined,
35+
innerHeight: (undefined: any),
36+
innerWidth: (undefined: any),
2137
screen: {
22-
height: undefined,
23-
width: undefined
38+
height: (undefined: any),
39+
width: (undefined: any)
2440
}
2541
};
2642

2743
const dimensions = {};
2844
const listeners = {};
2945

3046
export default class Dimensions {
31-
static get(dimension: string): Object {
47+
static get(dimension: DimensionKey): DisplayMetrics {
3248
invariant(dimensions[dimension], `No dimension set for key ${dimension}`);
3349
return dimensions[dimension];
3450
}
3551

36-
static set(initialDimensions: ?{ [key: string]: any }): void {
52+
static set(initialDimensions: ?DimensionsValue): void {
3753
if (initialDimensions) {
3854
if (canUseDOM) {
3955
invariant(false, 'Dimensions cannot be set in the browser');
@@ -64,12 +80,18 @@ export default class Dimensions {
6480
}
6581
}
6682

67-
static addEventListener(type: string, handler: Function): void {
83+
static addEventListener(
84+
type: DimensionEventListenerType,
85+
handler: DimensionsValue => void
86+
): void {
6887
listeners[type] = listeners[type] || [];
6988
listeners[type].push(handler);
7089
}
7190

72-
static removeEventListener(type: string, handler: Function): void {
91+
static removeEventListener(
92+
type: DimensionEventListenerType,
93+
handler: DimensionsValue => void
94+
): void {
7395
if (Array.isArray(listeners[type])) {
7496
listeners[type] = listeners[type].filter(_handler => _handler !== handler);
7597
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow strict-local
9+
*/
10+
11+
'use strict';
12+
13+
import type { DisplayMetrics } from '../Dimensions';
14+
15+
import Dimensions from '../Dimensions';
16+
import { useEffect, useState } from 'react';
17+
18+
export default function useWindowDimensions(): DisplayMetrics {
19+
const [dims, setDims] = useState(() => Dimensions.get('window'));
20+
useEffect(() => {
21+
function handleChange({ window }) {
22+
// $FlowFixMe
23+
setDims(window);
24+
}
25+
Dimensions.addEventListener('change', handleChange);
26+
// We might have missed an update between calling `get` in render and
27+
// `addEventListener` in this handler, so we set it here. If there was
28+
// no change, React will filter out this update as a no-op.
29+
setDims(Dimensions.get('window'));
30+
return () => {
31+
Dimensions.removeEventListener('change', handleChange);
32+
};
33+
}, []);
34+
return dims;
35+
}

packages/react-native-web/src/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ import TVEventHandler from './exports/TVEventHandler';
7373
// plugins
7474
import DeviceEventEmitter from './exports/DeviceEventEmitter';
7575

76+
// hooks
77+
import useWindowDimensions from './exports/useWindowDimensions';
78+
7679
export {
7780
// top-level API
7881
createElement as unstable_createElement,
@@ -145,5 +148,7 @@ export {
145148
TimePickerAndroid,
146149
TVEventHandler,
147150
// plugins
148-
DeviceEventEmitter
151+
DeviceEventEmitter,
152+
// hooks
153+
useWindowDimensions
149154
};

0 commit comments

Comments
 (0)