I'm developing a react-native app. I'm currently testing in android and it appears that when the app loses focus and then the launch icon is pressed again that the components are recreated without a call to componentWillUnmount.
I can recreate this with a trivial react-native app:
react-native init MultipleComponents
And adding the following to the App class:
componentDidMount() {
clearInterval(this._interval);
this._interval = setInterval(() => {
console.log("Timeout");
}, 5000);
}
componentWillUnmount() {
console.log("Timeout");
clearInterval(this._interval);
}
Once this is done run it with:
react-native run-android
Then on the emulator you can end up with multiple timers running by pressing the home button and relaunching the app. Having multiple timers running is obviously not ideal.
Note that componentWillUnmount is not called.
Am I missing something? How is this meant to be handled?
The JavaScript thread is gone when the app is not in the foreground, so no React code is executed after your app loses focus and this includes componentWillUnmount and other lifecycle methods.
But if you end up having multiple timers when pressing the icon, you should probably check your AndroidManifest.xml file for launchMode. If the value for launchMode is either standard or singleTop, then multiple instances of your app can exist. If you change the setting to singleInstance or singleTask there will always be just one instance.
android/app/src/AndroidManifest.xml:
<manifest>
<application>
<activity
android:launchMode="singleTask">
</application>
</manifest>
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 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
Our React Native project has both Segment and CodePush integrated.
Segment works fine, normally.
But there's a scenario where Segment stops working right after a CodePush update has been installed. Nothing gets flushed out and none of the events are shown in the Live Debugger list - except for events that are tracked in the native layer (eg: "Application Opened" and "Application Backgrounded" - only these show up).
So I assumed that any Segment call in the RN - Javascript layer only stops working after the app restarts the bundle (by CodePush).
The user should close and kill the app and reopen the app for it to work normally again.
Happens to both iOS and Android (when installed from the store).
And weirdly enough, I cannot recreate the issue on Android when I run a debug or release build directly to my Android phone from my machine (it just works 🤷♂️). Same goes for iOS simulators.
Any ideas or workarounds on this?
This is how the setup looks like:
import React, { Component } from "react";
import CodePush from "react-native-code-push";
import segment from "#segment/analytics-react-native";
...
class App extends Component {
constructor(props) {
super(props);
this.setupSegment();
}
private setupSegment(): void {
segment.setup("<Segment Write Key>", {
debug: true,
trackAppLifecycleEvents: true,
ios: {
trackAdvertising: true
}
});
}
...
}
export default CodePush({
installMode: CodePush.InstallMode.IMMEDIATE,
checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
updateDialog: null
})(App);
react-native: 0.61.5
react-native-code-push: 6.1.0
#segment/analytics-react-native: 1.1.1-beta.2 (also tried 1.1.1-beta.5)
I am working on React Native Application and integrated react-native-navigation package for navigation inside app, link of package
Android App got stuck and show blank screen. This happens if I am closing app using back button in case of Android app. At the end I have a listing screen, after reopen the application it shows blank screen because it's not calling Navigation.registerComponent again, it might be destroying app when closed using back button.
This is a code inside my index.js::
import { Navigation } from "react-native-navigation";
import App from './src/app';
Navigation.registerComponent("appName", () => App);
Killing the app and restarting would fix the stuck on splash screen issue. But shouldn't be stuck in the first place. Just an issue when closing through back button.
Does anyone have a fix for this? Please suggest how can I handle and call my Navigation.registerComponent once again after closing app using back button.
Environment
React Native Navigation version: 2.12.0
React Native version: 0.58
Platform(s) : Android only
To resolve this you need to make modification inside react-native-navigation package. Open NavigationActivity.java file and replace below code with new one:
Replace this code:
#Override
public void invokeDefaultOnBackPressed() {
if (!navigator.handleBack(new CommandListenerAdapter())) {
super.onBackPressed();
}
}
With this one:
#Override
public void invokeDefaultOnBackPressed() {
if (!navigator.handleBack(new CommandListenerAdapter())) {
this.moveTaskToBack(true);
//super.onBackPressed();
}
}
After saving your changes check on android device.
I'm creating an app visually similar to Alfred to manage and search for my bookmarks. Its working well, but when I do a search and open a bookmark, I immediately hide the app and when I invoke it again, it return to the default mode doing a visual flash. The reset to default is triggered right before hiding the app.
I hide the application like this : remote.app.hide() and I added a listener on win.hide in my components to reset the vue.
It works, but the reset is processed after the application show up again.
I don't know how to do it when the application is hide or to show up it right after the vue is reloaded.
If you have any clue, it would be great.
I created a sample project on Github you can clone and test this issue.
Github Project
I'm working on macOS at the moment.
Thank you.
I found an easy way, you cannot rely on the window.on('hide') event.
So in your shortcut registration, I made your app emit a custom event that your Vue.js will listen to reset your input before hiding the app:
main.js
const retShow = globalShortcut.register('CmdOrCtrl+Alt+V', () => {
if (!win.isVisible()) {
win.show()
} else {
app.emit('hide-window'); // Let the window hide the app
}
})
In your Vue.js app, in the created hook:
app.js
app.on('hide-window', function () {
vm.reset();
setTimeout(app.hide, 10);
});
Here my pull request: https://github.com/Cronos87/electron-vue-flash-issue/pull/1/files