I am developing an app with React Native. I want to implement the ability to save locations when the app is in the background or closed state. For this purpose, I am using 'react-native-background-fetch'.
According to the instructions for 'react-native-background-fetch,' I need to set the enableHeadless option to 'true' to enable React Native's Headless JS mechanism for handling fetch events after the app is terminated.
So I made the code as below.
Belows are my code.
index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import {Amplify} from 'aws-amplify';
import amplifyconfig from './src/amplifyconfiguration.json';
Amplify.configure(amplifyconfig);
import BackgroundFetch from 'react-native-background-fetch';
import {saveLocationInContext} from './src/context/CommonContext';
let MyHeadlessTask = async event => {
// Get task id from event {}:
let taskId = event.taskId;
let isTimeout = event.timeout; // <-- true when your background-time has expired.
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing immediately finish(taskId)
console.log('[BackgroundFetch] Headless TIMEOUT:', taskId);
BackgroundFetch.finish(taskId);
return;
}
console.log('[BackgroundFetch HeadlessTask] start: ', taskId);
// Perform an example HTTP request.
// Important: await asychronous tasks when using HeadlessJS.
const location = await saveLocationInContext('auto');
console.log('[BackgroundFetch HeadlessTask] location: ', location);
// Required: Signal to native code that your task is complete.
// If you don't do this, your app could be terminated and/or assigned
// battery-blame for consuming too much time in background.
BackgroundFetch.finish(taskId);
};
// Register your BackgroundFetch HeadlessTask
BackgroundFetch.registerHeadlessTask(MyHeadlessTask);
AppRegistry.registerComponent(appName, () => App);
CommonContext.js
...
...
const CommonContext = createContext({});
const CommonContextProvider = ({children}) => {
...
...
return (
<CommonContext.Provider
value={{
requestLocationPermission,
location,
getLocation,
}}>
{children}
</CommonContext.Provider>
);
};
export const saveLocationInContext = async remark => {
const {getLocation} = useCommonContext();
const {dbUser} = useAuthContext();
if (!dbUser) {
console.error('No user information');
return;
}
try {
const location = await getLocation();
const savedAttendance = await DataStore.save(
new StaffAttandance({
userId: dbUser.id,
userName: dbUser.userName,
latitude: location.latitude,
longitude: location.longitude,
remark: remark,
}),
);
console.log('index.js', new Date());
return location;
} catch (err) {
console.error('CommonContext saveLocation', err);
}
};
export default CommonContextProvider;
export const useCommonContext = () => useContext(CommonContext);
However, I encountered the following errors.
LOG [BackgroundFetch HeadlessTask] start: react-native-background-fetch
ERROR Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
ERROR [TypeError: Cannot read property 'useContext' of null]
LOG [BackgroundFetch] Headless TIMEOUT: react-native-background-fetch
As I am new to React Native, I am not sure what I did wrong. If you have any insights, please help.
Thanks.