[fix] AppState event handler registration

Fix #151
This commit is contained in:
Nicolas Gallagher
2016-06-21 14:57:53 -07:00
parent eca2f69593
commit af40f98f23
6 changed files with 67 additions and 16 deletions
+1 -2
View File
@@ -37,7 +37,6 @@ class Example extends React.Component {
constructor(props) {
super(props)
this.state = { currentAppState: AppState.currentState }
this._handleAppStateChange = this._handleAppStateChange.bind(this)
}
componentDidMount() {
@@ -48,7 +47,7 @@ class Example extends React.Component {
AppState.removeEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange(currentAppState) {
_handleAppStateChange = (currentAppState) => {
this.setState({ currentAppState });
}
+4 -1
View File
@@ -1,7 +1,10 @@
import { AppRegistry } from 'react-native'
import App from './components/App'
import Game2048 from './2048/Game2048'
import TicTacToeApp from './TicTacToe/TicTacToe'
AppRegistry.runApplication('TicTacToeApp', {
AppRegistry.registerComponent('App', () => App)
AppRegistry.runApplication('App', {
rootTag: document.getElementById('react-root')
})
+1 -1
View File
@@ -19,7 +19,7 @@
"babel-runtime": "^6.9.2",
"fbjs": "^0.8.1",
"inline-style-prefix-all": "1.0.5",
"lodash.debounce": "^4.0.6",
"lodash": "^4.13.1",
"react-textarea-autosize": "^4.0.2",
"react-timer-mixin": "^0.13.3"
},
+27 -1
View File
@@ -1,5 +1,31 @@
/* eslint-env mocha */
import AppState from '..'
import assert from 'assert'
suite('apis/AppState', () => {
test.skip('NO TEST COVERAGE', () => {})
const handler = () => {}
teardown(() => {
try { AppState.removeEventListener('change', handler) } catch (e) {}
})
suite('addEventListener', () => {
test('throws if the provided "eventType" is not supported', () => {
assert.throws(() => AppState.addEventListener('foo', handler))
assert.doesNotThrow(() => AppState.addEventListener('change', handler))
})
})
suite('removeEventListener', () => {
test('throws if the handler is not registered', () => {
assert.throws(() => AppState.removeEventListener('change', handler))
})
test('throws if the provided "eventType" is not supported', () => {
AppState.addEventListener('change', handler)
assert.throws(() => AppState.removeEventListener('foo', handler))
assert.doesNotThrow(() => AppState.removeEventListener('change', handler))
})
})
})
+33 -10
View File
@@ -1,30 +1,53 @@
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'
import findIndex from 'lodash/findIndex'
import invariant from 'fbjs/lib/invariant'
const listeners = {}
const eventTypes = [ 'change' ]
const EVENT_TYPES = [ 'change' ]
const VISIBILITY_CHANGE_EVENT = 'visibilitychange'
const AppStates = {
BACKGROUND: 'background',
ACTIVE: 'active'
}
const listeners = []
class AppState {
static isSupported = ExecutionEnvironment.canUseDOM && document.visibilityState
static get currentState() {
if (!AppState.isSupported) {
return AppState.ACTIVE
}
switch (document.visibilityState) {
case 'hidden':
case 'prerender':
case 'unloaded':
return 'background'
return AppStates.BACKGROUND
default:
return 'active'
return AppStates.ACTIVE
}
}
static addEventListener(type: string, handler: Function) {
listeners[handler] = () => handler(AppState.currentState)
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type)
document.addEventListener('visibilitychange', listeners[handler], false)
if (AppState.isSupported) {
invariant(EVENT_TYPES.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type)
const callback = () => handler(AppState.currentState)
listeners.push([ handler, callback ])
document.addEventListener(VISIBILITY_CHANGE_EVENT, callback, false)
}
}
static removeEventListener(type: string, handler: Function) {
invariant(eventTypes.indexOf(type) !== -1, 'Trying to remove listener for unknown event: "%s"', type)
document.removeEventListener('visibilitychange', listeners[handler], false)
delete listeners[handler]
if (AppState.isSupported) {
invariant(EVENT_TYPES.indexOf(type) !== -1, 'Trying to remove listener for unknown event: "%s"', type)
const listenerIndex = findIndex(listeners, (pair) => pair[0] === handler)
invariant(listenerIndex !== -1, 'Trying to remove AppState listener for unregistered handler')
const callback = listeners[listenerIndex][1]
document.removeEventListener(VISIBILITY_CHANGE_EVENT, callback, false)
listeners.splice(listenerIndex, 1)
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
* @flow
*/
import debounce from 'lodash.debounce'
import debounce from 'lodash/debounce'
import React, { Component, PropTypes } from 'react'
import View from '../View'