Faced the same issue these last days.
I've finally managed it by deporting my app state management to my App.js component and created a service manager.
Here quickly how my App.js
look like:
import {AppState } from "react-native";
import {AppStateService} from "YOUR_PATH_TO_THE_NEXT_FILE";
export default function App() {
// Listen to app state
AppStateService.init();
useEffect(() => {
AppState.addEventListener('change', AppStateService.getInstance().handleAppStateChange);
return (() => {
AppState.removeEventListener('change', AppStateService.getInstance().handleAppStateChange);
})
}, []);
return (/*Rendering stuff (navigation, error boundary, ...*/);
}
AppStateService.js
:
/**
* Class to allow us to refer to the app state service
*/
export class AppStateService {
static instance;
static STATE_ACTIVE = 'active';
static STATE_INACTIVE = 'inactive';
static STATE_BACKGROUND = 'background';
static STATE_NOT_LAUNCHED = 'not_launched';
previousState = AppStateService.STATE_NOT_LAUNCHED;
currentState = AppStateService.STATE_ACTIVE;
handlers = {};
appLaunchId = 0;
/**
* @returns {AppStateService}
*/
static getInstance() {
if(!this.instance){
this.instance = new AppStateService();
}
return this.instance;
}
static init = () => {
// This func need to be call in the App.js, it's just here to create the instance
const instance = AppStateService.getInstance();
instance.appLaunchId = new Date().getTime() / 1000;
}
handleAppStateChange = (nextState) => {
if(nextState !== this.currentState) {
this.previousState = this.currentState;
this.currentState = nextState;
for (const [key, handler] of Object.entries(this.handlers)) {
handler(nextState);
}
}
}
getCurrentState = () => {
return this.currentState;
}
getPreviousState = () => {
return this.previousState;
}
addStateHandler = (key, handler) => {
this.handlers[key] = handler;
}
hasStateHandler = (key) => {
if( this.handlers[key] ){
return true;
}
return false;
}
removeStateHandler = (key) => {
delete this.handlers[key];
}
}
and now here is how to call it from anywhere you want in your app components:
export default class RandomComponent extends React.Component {
componentDidMount() {
// Check app going background or not
this.handleAppStateChange = this.handleAppStateChange.bind(this);
AppStateService.getInstance().addStateHandler('myListenerCustomKey', this.handleAppStateChange);
}
componentWillUnmount() {
// Remove app state change listener
AppStateService.getInstance().removeStateHandler('myListenerCustomKey');
}
handleAppStateChange = (nextAppState) => {
console.log("I'm going to be -" + nextAppState + "- while I was -" + AppStateService.getInstance().getPreviousState() + "-");
}
}
This way you have the capability to listen everywhere in your app to the app foreground/inactive/background state and correctly subscribe/unsubscribe to those events.