Skip to content

Commit

Permalink
Updated AppState module to use new emitter system
Browse files Browse the repository at this point in the history
Summary: AppState now subclasses NativeEventEmitter instead of using global RCTDeviceEventEmitter.

Reviewed By: javache

Differential Revision: D3310488

fbshipit-source-id: f0116599223f4411307385c0dab683659d8d63b6
  • Loading branch information
nicklockwood authored and Facebook Github Bot 3 committed May 23, 2016
1 parent c87b737 commit d973757
Show file tree
Hide file tree
Showing 20 changed files with 186 additions and 263 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ @implementation SizeFlexibilityTestDelegate

- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

[rootView.bridge.eventDispatcher sendAppEventWithName:@"rootViewDidChangeIntrinsicSize"
body:@{@"width": @(rootView.intrinsicSize.width),
@"height": @(rootView.intrinsicSize.height)}];
#pragma clang diagnostic pop
}

@end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,13 @@ - (void)testLegacyEventsAreImmediatelyDispatched
[[_bridge expect] enqueueJSCall:_JSMethod
args:[_testEvent arguments]];

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

[_eventDispatcher sendDeviceEventWithName:_eventName body:_body];

#pragma clang diagnostic pop

[_bridge verify];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ @implementation RCTTestViewManager

RCT_EXPORT_MODULE()

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"

- (NSArray<NSString *> *)customDirectEventTypes
{
return @[@"foo"];
}

#pragma clang diagnostic pop

@end


Expand Down
104 changes: 65 additions & 39 deletions Libraries/AppState/AppState.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,12 @@
*/
'use strict';

var Map = require('Map');
var NativeModules = require('NativeModules');
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var RCTAppState = NativeModules.AppState;
const NativeEventEmitter = require('NativeEventEmitter');
const NativeModules = require('NativeModules');
const RCTAppState = NativeModules.AppState;

var logError = require('logError');
var invariant = require('fbjs/lib/invariant');

var _eventHandlers = {
change: new Map(),
memoryWarning: new Map(),
};
const logError = require('logError');
const invariant = require('fbjs/lib/invariant');

/**
* `AppState` can tell you if the app is in the foreground or background,
Expand All @@ -36,8 +30,9 @@ var _eventHandlers = {
* - `active` - The app is running in the foreground
* - `background` - The app is running in the background. The user is either
* in another app or on the home screen
* - `inactive` - This is a transition state that currently never happens for
* typical React Native apps.
* - `inactive` - This is a state that occurs when transitioning between
* foreground & background, and during periods of inactivity such as
* entering the Multitasking view or in the event of an incoming call
*
* For more information, see
* [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)
Expand Down Expand Up @@ -75,13 +70,58 @@ var _eventHandlers = {
* state will happen only momentarily.
*/

var AppState = {
class AppState extends NativeEventEmitter {

/**
_eventHandlers: Object;
currentState: ?string;

constructor() {
super(RCTAppState);

this._eventHandlers = {
change: new Map(),
memoryWarning: new Map(),
};

// TODO: getCurrentAppState callback seems to be called at a really late stage

This comment has been minimized.

Copy link
@edgarkhanzadian

edgarkhanzadian Nov 27, 2017

Hi @nicklockwood ! As I understand you worked on this file like a year ago and left a lot of TODOs here. I can implement these TODOs if those are still relevant.
Best regards!

// after app launch. Trying to get currentState when mounting App component
// will likely to have the initial value here.
// Initialize to 'active' instead of null.
this.currentState = 'active';

// TODO: this is a terrible solution - in order to ensure `currentState` prop
// is up to date, we have to register an observer that updates it whenever
// the state changes, even if nobody cares. We should just deprecate the
// `currentState` property and get rid of this.
this.addListener(
'appStateDidChange',
(appStateData) => {
this.currentState = appStateData.app_state;
}
);

// TODO: see above - this request just populates the value of `currentState`
// when the module is first initialized. Would be better to get rid of the prop
// and expose `getCurrentAppState` method directly.
RCTAppState.getCurrentAppState(
(appStateData) => {
this.currentState = appStateData.app_state;
},
logError
);
}

/**
* Add a handler to AppState changes by listening to the `change` event type
* and providing the handler
*
* TODO: now that AppState is a subclass of NativeEventEmitter, we could deprecate
* `addEventListener` and `removeEventListener` and just use `addListener` and
* `listener.remove()` directly. That will be a breaking change though, as both
* the method and event names are different (addListener events are currently
* required to be globally unique).
*/
addEventListener: function(
addEventListener(
type: string,
handler: Function
) {
Expand All @@ -90,53 +130,39 @@ var AppState = {
'Trying to subscribe to unknown event: "%s"', type
);
if (type === 'change') {
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
this._eventHandlers[type].set(handler, this.addListener(
'appStateDidChange',
(appStateData) => {
handler(appStateData.app_state);
}
));
} else if (type === 'memoryWarning') {
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
this._eventHandlers[type].set(handler, this.addListener(
'memoryWarning',
handler
));
}
},
}

/**
* Remove a handler by passing the `change` event type and the handler
*/
removeEventListener: function(
removeEventListener(
type: string,
handler: Function
) {
invariant(
['change', 'memoryWarning'].indexOf(type) !== -1,
'Trying to remove listener for unknown event: "%s"', type
);
if (!_eventHandlers[type].has(handler)) {
if (!this._eventHandlers[type].has(handler)) {
return;
}
_eventHandlers[type].get(handler).remove();
_eventHandlers[type].delete(handler);
},

currentState: ('active' : ?string),
};

RCTDeviceEventEmitter.addListener(
'appStateDidChange',
(appStateData) => {
AppState.currentState = appStateData.app_state;
this._eventHandlers[type].get(handler).remove();
this._eventHandlers[type].delete(handler);
}
);
};

RCTAppState.getCurrentAppState(
(appStateData) => {
AppState.currentState = appStateData.app_state;
},
logError
);
AppState = new AppState();

module.exports = AppState;
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,8 @@
*/
'use strict';

var warning = require('fbjs/lib/warning');
const AppState = require('AppState');

class AppStateIOS {
console.warn('AppStateIOS is deprecated. Use AppState instead');

static addEventListener(type, handler) {
warning(false, 'Cannot listen to AppStateIOS events on Android.');
}

static removeEventListener(type, handler) {
warning(false, 'Cannot remove AppStateIOS listener on Android.');
}

}

AppStateIOS.currentState = null;

module.exports = AppStateIOS;
module.exports = AppState;
147 changes: 0 additions & 147 deletions Libraries/AppStateIOS/AppStateIOS.ios.js

This file was deleted.

Loading

0 comments on commit d973757

Please sign in to comment.