I have a functional component in my react native app that has an event listener watching the app state in order to clear out a cache when the app is closed. This works as expected, and I have logic written in a useEffect block to add/remove this event listener when the app is closed.
The functionality works perfectly when the user either navigates elsewhere in the app or closes the app, but when the app is re-opened after closing (not fully shutting down the app, just moving to a different app) the page is not re-rendered and so the event listener is not re-added.
I've attached the code in my useEffect below.
useEffect(() => {
if (!listenerRef.current) {
toggleEventListener(true);
}
return () => {
toggleEventListener(false);
};
}, []);
You can use appState from react-native to see foreground and background events
https://reactnative.dev/docs/appstate
Related
I am making a React Native app which talks to Spotify via this module: https://github.com/cjam/react-native-spotify-remote
The module has an event listener which allows us to listen to Spotify player state changes, for example:
import { remote as SpotifyRemote } from "react-native-spotify-remote";
// and in a React component:
SpotifyRemote.addListener("playerStateChanged", (state) => {
console.log(state);
});
The above works as long as our RN app is in focus. However, when the app is in the background (i.e. we are on a different app or the phone is locked), the event listner no longer gets triggered.
I am expecting the event listener to get triggered even when the app is running in the background but it isn't doing that.
Is there anyway to make this work even the app is not in focus? Thank you!
I setup notification system with firebase and react native. It's working fine, but when i receive notification in any state of app(killed, fore or background) and do click notification push me to home screen. I want to go on notification screen when someone click on notification.
How it will possible?
First, you have to add a Firebase Notification listener at the top-level component. I'll suggest placing it in App.js.
Foreground Listener
Background Listener
After that, You have to navigate to a particular screen with the help of a navigation prop. if you place the listener at App.js then you will not have access to the navigation prop since App.js will return the navigation container.
For that, you have to create one helper function like this navigation without prop
e.g.
export const App = () => {
messaging().setBackgroundMessageHandler(async remoteMessage => {
navigate('Notification'); //navigate to notification screen
});
const unsubscribe = messaging().onMessage(async remoteMessage => {
//generate local notification using your preferred library
//handle navigation
})
return <RootNavigator />;
};
I'm migrating an old React Native app from 0.57 to 0.62, and just setup navigation with the current React Navigation package. That app contains a global navigation store that registers to Android back button presses and allows me to intercept back operations, no matter where they originate (hardware button or programmatically).
I have a rather weird behavior here, and it seems to be timing-related. In the snippet below, I register a listener with BackHandler, which supresses back button taps and logs a warning. I'll register it in the componentDidMount method.
export class RootComponent extends React.Component {
private initBackButton() {
const onBackPress = () => {
console.warn("BACK BUTTON SUPPRESSED");
return true;
};
BackHandler.addEventListener("hardwareBackPress", onBackPress);
}
public componentDidMount() {
// TODO register back listener
}
public render() {
return (
<NavigationContainer >
<StackNavigatorSetup />
</NavigationContainer>
);
}
}
If I register the listener synchronously, the back button listener fires if I press it at the initial screen of my StackNavigator.
If I navigate to a second screen, the listener does not fire if I press the back button, and I can return back to the start screen. If I press back there again, the listener fires.
Note that I'm declaring the listener in the root component, so that component isn't going anywhere.
public componentDidMount() {
// only works on the start screen
this.initBackButton();
}
Now, the behavior is different if I use a delay:
If I register the same handler with a delay of 1 second, the handler works on any screen
This is not thread-related. If I use a delay that is too short, it again only works on the start screen
public componentDidMount() {
// works on every screen i'll navigate to
PromiseUtil.delay(1000).then(() => this.initBackButton());
}
To be honest, I don't really have a clue what's happening here. BackHandler seems to be ready, but I don't understand why the listener works either global or not depending on the delay. Also, my root component doesn't really change, so I wonder whether React Navigation is messing with me here...
I am working on react native application and my requirement is to launch specific screen on Notification received.
Notification is working fine in all state i.e. Foreground or background.
I am using below library:
react-navigation
#react-native-firebase/messaging
react-native-push-notification
Below is the code for handling notification :
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
let text = {
title: remoteMessage.data.title,
body: remoteMessage.data.body,
}
notif.cancelAll();
notif.localNotif(text);
NavigationService.navigate('Contact', { userName: 'Lucy' })
});
Also wrote a navigation code on notification received method referring
https://reactnavigation.org/docs/4.x/navigating-without-navigation-prop
I can see app navigate to particular screen but its not launching app.
Can anyone help me with this?
Please I need an example on how to use the 'blur' event for react native AppState. I am trying to respond to when the app is not in focus e.g. when the user pulls the notification drawer but I keep getting the error message Invariant Violation: Trying to subscribe to unknown event: "blur".
Based on the tags associated with the commit that this feature landed in (https://github.com/facebook/react-native/commit/d45818fe47c53a670db933cf805910e227aa79c9) it seems like that is only available starting in 0.61 and hasn't landed in a stable release yet. Make sure you're running 0.61.0-rc.0 or later.
According to documentation . Blur is [Android only]
"[Android only] Received when the user is not actively interacting with the app. Useful in situations when the user pulls down the notification drawer. AppState won't change but the blur event will get fired."
if you still want to use it for android you can use it with condition for android only
import { Platform } from "react-native";
........
componentDidMount() {
if (Platform.OS === "android") {
AppState.addEventListener("blur", this._handleAppStateBlur);
}
}
componentWillUnmount() {
if (Platform.OS === "android") {
AppState.removeEventListener("blur", this._handleAppStateBlur);
}
}
_handleAppStateBlur = () => {
console.log("blur");
};
According to the docs mentioned in the official react native documentation, there are three states supported by AppState:
active - The app is running in the foreground.
background - The app is running in the background. The user is either:
in another app
on the home screen
[Android] on another Activity (even if it was launched by your app)
[iOS] 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.
Since there is no such state as blur, therefore you are facing an error saying that it could not find such event.
Edit
You have to register blur as an event in your component lifecycle, but you have to be cautious here and have to determine the Platform before registering blur event as it is available in android only and not in ios.
To register an event you have to do this:
import React from 'react';
import {AppState} from 'react-native';
class HandlingEvents extends React.Pure.Component {
constructor(props) {
super(props)
// your state goes here...
}
componentDidMount() {
// your event will be registered here, when your component is mounted on // the screen.
// Be cautious here, make a platform check here so as to avoid discrepancies in ios devices
AppState.addEventListener('blur',this.handleBlurState)
}
componentWillUnMount() {
// your event will be removed here, when your component gets unmounted from the screen.
// Be cautious here, make a platform check here so as to avoid discrepancies in ios devices
AppState.removeEventListener('blur',this.handleBlurState)
}
handleBlurState = (nextAppState) => {
//this method will contain your entire logic, as to how you want to treat your component in this event.
// As per the docs, since the state of your app will not changed, therefore you can continue your logic here by checking if the state of your app is **change** or not..
if (AppState.currentState === "active" && nextAppState === "active") {
//whatever task you want to perform here..;
}
}
}