Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Updated AppState module to use new emitter system
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.
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
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
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
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;
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.

0 comments on commit d973757

Please sign in to comment.