Search code examples
background-processredux-saga

How to properly work with redux saga and background event in react native?


I am using react-native, redux-saga, react-native-background-task.

First, when my app goes from the foreground to the background (on both IOS and Android), saga continues. I would have expected it to stop, but I guess because saga is on another thread it continues. Is this going to cause issues for battery management or prevent IOS from allowing to app to execute background fetch events?

Second, when a background task starts, on the Android app my main saga starts like normal (not expected behavior, I would have thought only the background task code to run. On IOS, only the background task code runs as I would have expected. Why does the Android app start the whole saga again?

Third, when I use xcode to 'simulate background fetch' it was working for a little bit, but now it is closing whatever other app is open and not running the task code. Why is this?

Here is where I define my background task:

BackgroundTask.define(async () => {
    const now = moment().format("HH:mm:ss");
    console.log("Executing background task at: ", now);
    console.log("Test Test Test!");
    BackgroundTask.finish();
});

Here is where I schedule the background task and include redux:

import React from 'react';
import { SafeAreaView, View, StatusBar, Alert } from 'react-native';
import { Provider } from 'react-redux';
import { redux_store } from './redux/store';
import { AppContainer } from './helpers/navigation.js';
import { styles } from './styles/styles.js';
import ReduxRootConnection from './components/reduxRoot';
import { aws_configure } from './helpers/aws-configure';
import BackgroundTask from 'react-native-background-task'

aws_configure();

import { initPushNotifications } from './helpers/initPN';

export default class App extends React.Component {

    componentDidMount() {
        // TODO: add this back in
        // initPushNotifications()

        BackgroundTask.schedule();
        this.check_background_task_status();
    }

    async check_background_task_status() {
        const status = await BackgroundTask.statusAsync();
        console.log("BackgroundTask Status: ", status);
    }

    render() {
        return (
            <Provider store={redux_store}>
                <View style={{flex: 1}}>
                    <SafeAreaView style={styles.mainAppContainerStyle}>
                        <ReduxRootConnection>
                            <AppContainer/>
                        </ReduxRootConnection>
                    </SafeAreaView>
                </View>
            </Provider>
        );
    }
}

Solution

  • When a react native app is backgrounded on android it doesn't mean the activity is necessarily destroyed so your js code may continue to run for an indeterminate amount of time. Eventually it's likely your activity will be stopped if the user doesn't open it again but you can't know exactly when. You could use react native's AppState (https://facebook.github.io/react-native/docs/appstate) to cancel sagas that you wish cancelled when the app goes into the background.

    For the background task question, the implementation on android for BackgroundTask uses react native's headless js (https://facebook.github.io/react-native/docs/headless-js-android.html) which starts your entire app in the background. On ios there is no headless js so the implementation is different.