Skip to content

Commit 082d361

Browse files
committed
reactNativeUtils: Add useAppState
1 parent 7471f6e commit 082d361

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

src/reactNativeUtils.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
/* @flow strict-local */
22

3+
import React from 'react';
4+
import { AppState } from 'react-native';
5+
import type { AppStateValues } from 'react-native/Libraries/AppState/AppState';
36
// eslint-disable-next-line id-match
47
import type { ____ViewStyle_Internal } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
58

9+
import * as logging from './utils/logging';
610
import type { BoundedDiff } from './generics';
11+
import { typesEquivalent } from './generics';
712

813
// A copy of the same-named type in
914
// node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.js, for
@@ -21,3 +26,39 @@ export type ViewStylePropWithout<T: { ... }> = GenericStyleProp<
2126
// copying that.
2227
$ReadOnly<$Shape<BoundedDiff<____ViewStyle_Internal, T>>>,
2328
>;
29+
30+
/**
31+
* A hook for AppState's current state value, updated on 'change' events.
32+
*
33+
* Gives `null` if the state isn't one of the documented values
34+
* (AppStateValues), which the upstream types allow for the initial value,
35+
* and logs to Sentry in that unexpected case.
36+
*/
37+
export function useAppState(): null | AppStateValues {
38+
// Upstream has `?string`… probably they mean `AppStateValues`, but we'll
39+
// take them at their word and handle the differences by logging, to
40+
// prompt investigation if needed:
41+
// - nullish
42+
// - some string that's not an AppStateValues
43+
let initialState = AppState.currentState;
44+
45+
if (
46+
initialState == null
47+
|| (typeof initialState === 'string'
48+
&& initialState !== 'inactive'
49+
&& initialState !== 'background'
50+
&& initialState !== 'active')
51+
) {
52+
// If Flow errors here, adjust cases in the conditional.
53+
typesEquivalent<AppStateValues, 'inactive' | 'background' | 'active'>();
54+
logging.warn(`Unexpected AppState.currentState: ${initialState?.toString() ?? '[nullish]'}`);
55+
initialState = null;
56+
}
57+
58+
const [value, setValue] = React.useState(initialState);
59+
React.useEffect(() => {
60+
const sub = AppState.addEventListener('change', setValue);
61+
return () => sub.remove();
62+
}, []);
63+
return value;
64+
}

0 commit comments

Comments
 (0)