Skip to content

Commit 1266427

Browse files
netshadenecolas
authored andcommitted
[fix] AppState addEventListener returns subscription object
Close necolas#2129
1 parent 4aba2bd commit 1266427

File tree

4 files changed

+29
-26
lines changed

4 files changed

+29
-26
lines changed

packages/docs/src/pages/docs/apis/app-state.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Returns the current state of the app.
3636

3737
### Static methods
3838

39-
{% call macro.prop('addEventListener', '(type: ?string, listener: (boolean) => void) => void') %}
39+
{% call macro.prop('addEventListener', '(type: ?string, listener: (boolean) => void) => ?EmitterSubscription') %}
4040
Add a listener to `AppState` changes. Listen to the `"change"` event type. The handler is called with the app state value.
4141
{% endcall %}
4242

packages/examples/pages/app-state/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ export default function AppStatePage() {
1818
}));
1919
};
2020

21-
AppState.addEventListener('change', handleChange);
21+
const subscription = AppState.addEventListener('change', handleChange);
2222
return () => {
23-
AppState.removeEventListener('change', handleChange);
23+
subscription.remove();
2424
};
2525
}, []);
2626

packages/react-native-web/src/exports/AppState/__tests__/index-test.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ import AppState from '..';
55
describe('apis/AppState', () => {
66
const handler = () => {};
77

8-
afterEach(() => {
9-
try {
10-
AppState.removeEventListener('change', handler);
11-
} catch (e) {}
12-
});
13-
148
describe('addEventListener', () => {
159
test('throws if the provided "eventType" is not supported', () => {
1610
expect(() => AppState.addEventListener('foo', handler)).toThrow();
17-
expect(() => AppState.addEventListener('change', handler)).not.toThrow();
11+
expect(() => AppState.addEventListener('change', handler).remove()).not.toThrow();
1812
});
1913
});
2014

2115
describe('removeEventListener', () => {
22-
test('throws if the handler is not registered', () => {
23-
expect(() => AppState.removeEventListener('change', handler)).toThrow();
16+
beforeEach(() => {
17+
// removeEventListener logs a deprecation warning, ignore
18+
jest.spyOn(console, 'error');
19+
console.error.mockImplementation(() => {});
20+
});
21+
22+
afterEach(() => {
23+
console.error.mockRestore();
2424
});
2525

2626
test('throws if the provided "eventType" is not supported', () => {

packages/react-native-web/src/exports/AppState/index.js

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
*/
1010

1111
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
12-
import findIndex from 'array-find-index';
1312
import invariant from 'fbjs/lib/invariant';
13+
import EventEmitter from '../../vendor/react-native/emitter/_EventEmitter';
1414

1515
// Android 4.4 browser
1616
const isPrefixed =
@@ -25,7 +25,7 @@ const AppStates = {
2525
ACTIVE: 'active'
2626
};
2727

28-
const listeners = [];
28+
let changeEmitter = null;
2929

3030
export default class AppState {
3131
static isAvailable = canUseDOM && document[VISIBILITY_STATE_PROPERTY];
@@ -53,9 +53,19 @@ export default class AppState {
5353
type
5454
);
5555
if (type === 'change') {
56-
const callback = () => handler(AppState.currentState);
57-
listeners.push([handler, callback]);
58-
document.addEventListener(VISIBILITY_CHANGE_EVENT, callback, false);
56+
if (!changeEmitter) {
57+
changeEmitter = new EventEmitter();
58+
document.addEventListener(
59+
VISIBILITY_CHANGE_EVENT,
60+
() => {
61+
if (changeEmitter) {
62+
changeEmitter.emit('change', AppState.currentState);
63+
}
64+
},
65+
false
66+
);
67+
}
68+
return changeEmitter.addListener(type, handler);
5969
}
6070
}
6171
}
@@ -67,15 +77,8 @@ export default class AppState {
6777
'Trying to remove listener for unknown event: "%s"',
6878
type
6979
);
70-
if (type === 'change') {
71-
const listenerIndex = findIndex(listeners, (pair) => pair[0] === handler);
72-
invariant(
73-
listenerIndex !== -1,
74-
'Trying to remove AppState listener for unregistered handler'
75-
);
76-
const callback = listeners[listenerIndex][1];
77-
document.removeEventListener(VISIBILITY_CHANGE_EVENT, callback, false);
78-
listeners.splice(listenerIndex, 1);
80+
if (type === 'change' && changeEmitter) {
81+
changeEmitter.removeListener(handler);
7982
}
8083
}
8184
}

0 commit comments

Comments
 (0)