4
4
* This source code is licensed under the MIT license found in the
5
5
* LICENSE file in the root directory of this source tree.
6
6
*
7
+ * @flow strict-local
7
8
* @format
8
- * @flow
9
9
*/
10
10
11
+ import { type EventSubscription } from '../vendor/emitter/EventEmitter' ;
11
12
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter' ;
12
- import type EventSubscription from '../vendor/emitter/_EventSubscription' ;
13
- import type EmitterSubscription from '../vendor/emitter/_EmitterSubscription' ;
14
13
import logError from '../Utilities/logError' ;
15
- import EventEmitter from '../vendor/emitter/EventEmitter' ;
16
14
import NativeAppState from './NativeAppState' ;
17
- import invariant from 'invariant' ;
18
15
19
16
export type AppStateValues = 'inactive' | 'background' | 'active' ;
20
17
@@ -37,56 +34,48 @@ type NativeAppStateEventDefinitions = {
37
34
*
38
35
* See https://reactnative.dev/docs/appstate.html
39
36
*/
40
- class AppState extends NativeEventEmitter < NativeAppStateEventDefinitions > {
41
- _eventHandlers : {
42
- [ key : $Keys < AppStateEventDefinitions > ] : Map <
43
- /* Handler */ $FlowFixMe ,
44
- EventSubscription< NativeAppStateEventDefinitions , $FlowFixMe> ,
45
- > ,
46
- ...,
47
- } ;
48
- _supportedEvents : $ReadOnlyArray < $Keys < AppStateEventDefinitions >> = [
49
- 'change' ,
50
- 'memoryWarning' ,
51
- 'blur' ,
52
- 'focus' ,
53
- ] ;
54
- currentState : ?string ;
37
+ class AppState {
38
+ currentState : ?string = null ;
55
39
isAvailable : boolean ;
56
40
57
- constructor ( ) {
58
- super ( NativeAppState ) ;
59
-
60
- this . isAvailable = true ;
61
- this . _eventHandlers = this . _supportedEvents . reduce ( ( handlers , key ) => {
62
- handlers [ key ] = new Map ( ) ;
63
- return handlers ;
64
- } , { } ) ;
65
-
66
- this . currentState = NativeAppState . getConstants ( ) . initialAppState ;
67
-
68
- let eventUpdated = false ;
41
+ _emitter : ?NativeEventEmitter < NativeAppStateEventDefinitions > ;
69
42
70
- // TODO: this is a terrible solution - in order to ensure `currentState`
71
- // prop is up to date, we have to register an observer that updates it
72
- // whenever the state changes, even if nobody cares. We should just
73
- // deprecate the `currentState` property and get rid of this.
74
- this . addListener ( 'appStateDidChange' , appStateData => {
75
- eventUpdated = true ;
76
- this . currentState = appStateData . app_state ;
77
- } ) ;
78
-
79
- // TODO: see above - this request just populates the value of `currentState`
80
- // when the module is first initialized. Would be better to get rid of the
81
- // prop and expose `getCurrentAppState` method directly.
82
- NativeAppState . getCurrentAppState ( appStateData => {
83
- // It's possible that the state will have changed here & listeners need to be notified
84
- if ( ! eventUpdated && this . currentState !== appStateData . app_state ) {
43
+ constructor ( ) {
44
+ if ( NativeAppState == null ) {
45
+ this . isAvailable = false ;
46
+ } else {
47
+ this . isAvailable = true ;
48
+
49
+ const emitter : NativeEventEmitter < NativeAppStateEventDefinitions > = new NativeEventEmitter(
50
+ NativeAppState,
51
+ );
52
+ this._emitter = emitter;
53
+
54
+ this.currentState = NativeAppState.getConstants().initialAppState;
55
+
56
+ let eventUpdated = false;
57
+
58
+ // TODO: this is a terrible solution - in order to ensure `currentState`
59
+ // prop is up to date, we have to register an observer that updates it
60
+ // whenever the state changes, even if nobody cares. We should just
61
+ // deprecate the `currentState` property and get rid of this.
62
+ emitter.addListener('appStateDidChange', appStateData => {
63
+ eventUpdated = true ;
85
64
this . currentState = appStateData . app_state ;
86
- // $FlowExpectedError[incompatible-call]
87
- this . emit ( 'appStateDidChange' , appStateData ) ;
88
- }
89
- } , logError ) ;
65
+ } );
66
+
67
+ // TODO: see above - this request just populates the value of `currentState`
68
+ // when the module is first initialized. Would be better to get rid of the
69
+ // prop and expose `getCurrentAppState` method directly.
70
+ // $FlowExpectedError[incompatible-call]
71
+ NativeAppState.getCurrentAppState(appStateData => {
72
+ // It's possible that the state will have changed here & listeners need to be notified
73
+ if ( ! eventUpdated && this . currentState !== appStateData . app_state ) {
74
+ this . currentState = appStateData . app_state ;
75
+ emitter . emit ( 'appStateDidChange' , appStateData ) ;
76
+ }
77
+ } , logError ) ;
78
+ }
90
79
}
91
80
92
81
// TODO: now that AppState is a subclass of NativeEventEmitter, we could
@@ -103,133 +92,37 @@ class AppState extends NativeEventEmitter<NativeAppStateEventDefinitions> {
103
92
addEventListener < K : $Keys < AppStateEventDefinitions > > (
104
93
type : K ,
105
94
handler : ( ...$ElementType < AppStateEventDefinitions , K > ) => void ,
106
- ) : void {
107
- invariant (
108
- this . _supportedEvents . indexOf ( type ) !== - 1 ,
109
- 'Trying to subscribe to unknown event: "%s"' ,
110
- type,
111
- ) ;
112
-
95
+ ) : EventSubscription {
96
+ const emitter = this . _emitter ;
97
+ if ( emitter == null ) {
98
+ throw new Error ( 'Cannot use AppState when `isAvailable` is false.' ) ;
99
+ }
113
100
switch ( type ) {
114
- case 'change' : {
101
+ case 'change' :
115
102
// $FlowIssue[invalid-tuple-arity] Flow cannot refine handler based on the event type
116
103
const changeHandler : AppStateValues => void = handler ;
117
- this . _eventHandlers [ type ] . set (
118
- handler ,
119
- this . addListener ( 'appStateDidChange' , appStateData => {
120
- changeHandler ( appStateData . app_state ) ;
121
- } ) ,
122
- ) ;
123
- break ;
124
- }
125
- case 'memoryWarning ': {
104
+ return emitter . addListener ( 'appStateDidChange' , appStateData => {
105
+ changeHandler ( appStateData . app_state ) ;
106
+ } ) ;
107
+ case 'memoryWarning' :
126
108
// $FlowIssue[invalid-tuple-arity] Flow cannot refine handler based on the event type
127
109
const memoryWarningHandler : ( ) = > void = handler ;
128
- this . _eventHandlers [ type ] . set (
129
- handler ,
130
- this . addListener ( 'memoryWarning' , memoryWarningHandler ) ,
131
- ) ;
132
- break ;
133
- }
134
-
110
+ return emitter . addListener ( 'memoryWarning' , memoryWarningHandler ) ;
135
111
case 'blur' :
136
- case 'focus ': {
112
+ case 'focus' :
137
113
// $FlowIssue[invalid-tuple-arity] Flow cannot refine handler based on the event type
138
114
const focusOrBlurHandler : ( ) = > void = handler ;
139
- this . _eventHandlers [ type ] . set (
140
- handler ,
141
- this . addListener ( 'appStateFocusChange' , hasFocus => {
142
- if ( type === 'blur' && ! hasFocus ) {
143
- focusOrBlurHandler ( ) ;
144
- }
145
- if ( type === 'focus' && hasFocus ) {
146
- focusOrBlurHandler ( ) ;
147
- }
148
- } ) ,
149
- ) ;
150
- }
151
- }
152
- }
153
-
154
- /**
155
- * Remove a handler by passing the `change` event type and the handler.
156
- *
157
- * See https://reactnative.dev/docs/appstate.html#removeeventlistener
158
- */
159
- removeEventListener < K : $Keys < AppStateEventDefinitions >> (
160
- type : K ,
161
- handler : ( ...$ElementType < AppStateEventDefinitions , K > ) => void ,
162
- ) {
163
- invariant (
164
- this . _supportedEvents . indexOf ( type ) !== - 1 ,
165
- 'Trying to remove listener for unknown event: "%s"' ,
166
- type,
167
- ) ;
168
- const subscription = this . _eventHandlers [ type ] . get ( handler ) ;
169
- if ( ! subscription ) {
170
- return;
115
+ return emitter . addListener ( 'appStateFocusChange' , hasFocus => {
116
+ if ( type === 'blur' && ! hasFocus ) {
117
+ focusOrBlurHandler ( ) ;
118
+ }
119
+ if ( type === 'focus' && hasFocus ) {
120
+ focusOrBlurHandler ( ) ;
121
+ }
122
+ } ) ;
171
123
}
172
- subscription . remove ( ) ;
173
- this . _eventHandlers [ type ] . delete ( handler ) ;
174
- }
175
- }
176
-
177
- class MissingNativeModuleError extends Error {
178
- constructor ( ) {
179
- super (
180
- 'Cannot use AppState module when native RCTAppState is not included in the build.\n' +
181
- 'Either include it, or check AppState.isAvailable before calling any methods.' ,
182
- ) ;
183
- }
184
- }
185
-
186
- class MissingNativeAppStateShim extends EventEmitter < NativeAppStateEventDefinitions > {
187
- // AppState
188
- isAvailable : boolean = false ;
189
- currentState : ?string = null ;
190
-
191
- addEventListener < K : $Keys < AppStateEventDefinitions >> (
192
- type : K ,
193
- handler : ( ...$ElementType < AppStateEventDefinitions , K > ) => mixed ,
194
- ) : void {
195
- throw new MissingNativeModuleError ( ) ;
196
- }
197
-
198
- removeEventListener < K : $Keys < AppStateEventDefinitions >> (
199
- type : K ,
200
- handler : ( ...$ElementType < AppStateEventDefinitions , K > ) => mixed ,
201
- ) {
202
- throw new MissingNativeModuleError ( ) ;
203
- }
204
-
205
- // $FlowIssue[invalid-tuple-arity]
206
- addListener < K : $Keys < NativeAppStateEventDefinitions >> (
207
- eventType : K ,
208
- // $FlowIssue[incompatible-extend]
209
- listener : ( ...$ElementType < NativeAppStateEventDefinitions , K > ) => mixed ,
210
- context : $FlowFixMe ,
211
- ) : EmitterSubscription < NativeAppStateEventDefinitions , K > {
212
- throw new MissingNativeModuleError ( ) ;
213
- }
214
-
215
- removeAllListeners < K : $Keys < NativeAppStateEventDefinitions >> (
216
- eventType : ?K ,
217
- ) : void {
218
- throw new MissingNativeModuleError ( ) ;
219
- }
220
-
221
- removeSubscription < K : $Keys < NativeAppStateEventDefinitions >> (
222
- subscription : EmitterSubscription < NativeAppStateEventDefinitions , K > ,
223
- ) : void {
224
- throw new MissingNativeModuleError ( ) ;
124
+ throw new Error ( 'Trying to subscribe to unknown event: ' + type ) ;
225
125
}
226
126
}
227
127
228
- // This module depends on the native `RCTAppState` module. If you don't include it,
229
- // `AppState.isAvailable` will return `false`, and any method calls will throw.
230
- // We reassign the class variable to keep the autodoc generator happy.
231
- const AppStateInstance : AppState | MissingNativeAppStateShim = NativeAppState
232
- ? new AppState ( )
233
- : new MissingNativeAppStateShim ( ) ;
234
-
235
- module . exports = AppStateInstance ;
128
+ module . exports = ( new AppState ( ) : AppState ) ;
0 commit comments