Skip to content

Commit be7ef24

Browse files
authored
fix: rely on screen dimensions instead of window dimensions (#948)
## 📜 Description Rely on screen dimensions instead of window dimensions. ## 💡 Motivation and Context Hook `useWindowDimensions` relies on `window` dimensions. Internally for `window` react-native uses `[RCTKeyWindowValuesProxy sharedInstance].windowSize` which may be not updated when screen gets rotated (in some cases), while `mainScreen.bounds.size` (that is used for `screen` dimensions) gets updated. So it looks like it's better to rely on `screen` instead of `window` to handle screen rotation cases. Last, but not least: react-native subscribes to rotation events, but doesn't call `beginGeneratingDeviceOrientationNotifications`. Without invoking this function `useWindowDimensions` will not receive updates when screen is getting rotated. At the moment it works, because other libs (`expo-screen-orientation`, `react-native-screens` are calling this method), but I think it also should be fixed in `react-native` core at some point of time. Closes #915 ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### JS - create custom implementation for `useWindowDimensions` for all platforms except Android; ## 🤔 How Has This Been Tested? Tested manually in repro app. Verified additionally be e2e tests 🤞 ## 📸 Screenshots (if appropriate): |Before|After| |-------|-----| |![image](https://github.com/user-attachments/assets/4d495888-2560-4cb1-afaf-4895feaf3769)|![image](https://github.com/user-attachments/assets/e4802906-5734-4d0c-b0d8-2d64993b82d3)| ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent aa1fa7d commit be7ef24

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed
Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,53 @@
1-
export { useWindowDimensions } from "react-native";
1+
import { useEffect, useState } from "react";
2+
import { Dimensions } from "react-native";
3+
4+
import type { WindowDimensionsEventData } from "../../types";
5+
6+
const screen = Dimensions.get("screen");
7+
8+
let initialDimensions: WindowDimensionsEventData = {
9+
width: screen.width,
10+
height: screen.height,
11+
};
12+
13+
Dimensions.addEventListener("change", (e) => {
14+
initialDimensions = {
15+
width: e.screen.width,
16+
height: e.screen.height,
17+
};
18+
});
19+
20+
/**
21+
* On iOS we need to use `screen`, because this property is derived from `mainScreen.bounds.size`
22+
* while `window` is based on `[RCTKeyWindowValuesProxy sharedInstance].windowSize`, which can have
23+
* out of date values (especially when device gets rotated).
24+
*
25+
* @returns Window dimension.
26+
* @example
27+
* ```
28+
* const { height, window } = useWindowDimensions();
29+
* ```
30+
*/
31+
export const useWindowDimensions = () => {
32+
const [dimensions, setDimensions] = useState(initialDimensions);
33+
34+
useEffect(() => {
35+
const subscription = Dimensions.addEventListener("change", (e) => {
36+
setDimensions({
37+
width: e.screen.width,
38+
height: e.screen.height,
39+
});
40+
});
41+
42+
// we might have missed an update between reading a value in render and
43+
// `addListener` in this handler, so we set it here. If there was
44+
// no change, React will filter out this update as a no-op.
45+
setDimensions(initialDimensions);
46+
47+
return () => {
48+
subscription.remove();
49+
};
50+
}, []);
51+
52+
return dimensions;
53+
};

0 commit comments

Comments
 (0)