Expo Location, Expo Task Manager with Context API react native - react-native

import React, { createContext, useContext, useState, useEffect } from 'react';
import {
authenticationService,
getUserProfileService,
} from '../services/user-service';
import { getDonationHistory } from '../services/donation-service';
import AsyncStorage from '#react-native-async-storage/async-storage';
import * as TaskManager from 'expo-task-manager';
import * as Location from 'expo-location';
import * as BackgroundFetch from 'expo-background-fetch';
const UserInfoContext = createContext();
const UserInfoProvider = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [userProfile, setUserProfile] = useState({
donorId: '',
icNo: '',
fName: '',
lName: '',
bloodType: '',
});
const [errorMessage, setErrorMessage] = useState(null);
const [location, setLocation] = useState({ latitude: '', longitude: '' });
let updateLocation = (loc) => {
setLocation(loc);
};
console.log(location);
const sendBackgroundLocation = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status === 'granted') {
const { status } = await Location.requestBackgroundPermissionsAsync();
if (status === 'granted') {
await Location.startLocationUpdatesAsync('LocationUpdate', {
accuracy: Location.Accuracy.Balanced,
timeInterval: 10000,
distanceInterval: 1,
foregroundService: {
notificationTitle: 'Live Tracker',
notificationBody: 'Live Tracker is on.',
},
});
}
}
};
const _requestLocationPermission = async () => {
(async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status == 'granted') {
let { status } = await Location.requestBackgroundPermissionsAsync();
if (status == 'granted') {
} else {
console.log('Permission to access location was denied');
}
} else {
console.log('Permission to access location was denied');
}
})();
};
sendBackgroundLocation();
const getUserProfile = () => {
return userProfile;
};
useEffect(() => {
(async () => await _requestLocationPermission())();
retrieveAuthTokens();
retrieveUserProfile();
});
let retrieveAuthTokens = async () => {
try {
const authTokens = await AsyncStorage.getItem('authTokens');
authTokens ? setIsLoggedIn(true) : setIsLoggedIn(false);
} catch (error) {
console.log(error.message);
}
};
let retrieveUserProfile = async () => {
try {
const userProfile = JSON.parse(await AsyncStorage.getItem('userProfile'));
userProfile
? setUserProfile({
donorId: userProfile.donorId,
icNo: userProfile.appUser.username,
fName: userProfile.fName,
lName: userProfile.lName,
bloodType: userProfile.bloodType,
})
: null;
} catch (error) {
console.log(error.message);
}
};
let loginUser = (values) => {
authenticationService(values)
.then(async (data) => {
if (data !== undefined && data !== null) {
const tokens = data.data;
await AsyncStorage.setItem('authTokens', JSON.stringify(tokens));
getProfile(values.icNo);
getHistories(userProfile.donorId);
setErrorMessage(null);
} else {
setErrorMessage('Wrong email/password!');
}
})
.catch((error) => console.log(error.message));
};
let logoutUser = async () => {
try {
await AsyncStorage.clear().then(console.log('clear'));
setIsLoggedIn(false);
} catch (error) {
console.log(error.message);
}
};
getProfile = (icNo) => {
getUserProfileService(icNo)
.then(async (res) => {
if (res !== undefined && res !== null) {
const profile = res.data;
await AsyncStorage.setItem('userProfile', JSON.stringify(profile));
setIsLoggedIn(true);
}
})
.catch((error) => console.log(error.message));
};
const getHistories = (userId) => {
getDonationHistory(userId)
.then(async (res) => {
if (res !== undefined && res !== null) {
const historyData = res.data;
await AsyncStorage.setItem(
'donationHistories',
JSON.stringify(historyData)
);
} else {
console.log('no data');
}
})
.catch((error) => console.log(error.message));
};
let contextData = {
loginUser: loginUser,
logoutUser: logoutUser,
isLoggedIn: isLoggedIn,
errorMessage: errorMessage,
userProfile: userProfile,
getHistories: getHistories,
};
return (
<UserInfoContext.Provider value={contextData}>
{children}
</UserInfoContext.Provider>
);
};
export const useUserInfo = () => useContext(UserInfoContext);
export default UserInfoProvider;
function myTask() {
try {
const backendData = 'Simulated fetch ' + Math.random();
return backendData
? BackgroundFetch.BackgroundFetchResult.NewData
: BackgroundFetch.BackgroundFetchResult.NoData;
} catch (err) {
return BackgroundFetch.BackgroundFetchResult.Failed;
}
}
async function initBackgroundFetch(taskName, interval = 60 * 15) {
try {
if (!TaskManager.isTaskDefined(taskName)) {
TaskManager.defineTask(taskName, ({ data, error }) => {
if (error) {
console.log('Error bg', error);
return;
}
if (data) {
const { locations } = data;
console.log(
locations[0].coords.latitude,
locations[0].coords.longitude
);
//-----------------doesnt work ----------------------------
UserInfoProvider.updateLocation({
latitude: locations[0].coords.latitude,
longitude: locations[0].coords.longitude,
});
//-----------------doesnt work ----------------------------
}
});
}
const options = {
minimumInterval: interval, // in seconds
};
await BackgroundFetch.registerTaskAsync(taskName, options);
} catch (err) {
console.log('registerTaskAsync() failed:', err);
}
}
initBackgroundFetch('LocationUpdate', 5);
I'm trying to update the location state in the UserInfoProvider and this location info will be sent to the firestore along with the userprofile details retrieved in this provider.
However, it seems that i cant access the
UserInfoProvider.updateLocation()
outside the UserInfoProvider component.
Is there anyway I can get both the userprofile info and the location info retrieved from background task together and send them to firestore?
At the moment, only the
console.log(
locations[0].coords.latitude,
locations[0].coords.longitude
);
in the background task seems to be working.
Error I got:
TaskManager: Task "LocationUpdate" failed:, [TypeError: undefined is
not a function (near '...UserInfoProvider.updateLocation...')] at
node_modules\react-native\Libraries\LogBox\LogBox.js:149:8 in
registerError at
node_modules\react-native\Libraries\LogBox\LogBox.js:60:8 in errorImpl
at node_modules\react-native\Libraries\LogBox\LogBox.js:34:4 in
console.error at
node_modules\expo\build\environment\react-native-logs.fx.js:27:4 in
error at node_modules\expo-task-manager\build\TaskManager.js:143:16 in
eventEmitter.addListener$argument_1 at
node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch at
node_modules\regenerator-runtime\runtime.js:294:29 in invoke at
node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch at
node_modules\regenerator-runtime\runtime.js:155:27 in invoke at
node_modules\regenerator-runtime\runtime.js:190:16 in
PromiseImpl$argument_0 at
node_modules\react-native\node_modules\promise\setimmediate\core.js:45:6
in tryCallTwo at
node_modules\react-native\node_modules\promise\setimmediate\core.js:200:22 in doResolve at
node_modules\react-native\node_modules\promise\setimmediate\core.js:66:11
in Promise at node_modules\regenerator-runtime\runtime.js:189:15 in
callInvokeWithMethodAndArg at
node_modules\regenerator-runtime\runtime.js:212:38 in enqueue at
node_modules\regenerator-runtime\runtime.js:239:8 in exports.async at
node_modules\expo-task-manager\build\TaskManager.js:133:57 in
eventEmitter.addListener$argument_1 at
node_modules\react-native\Libraries\vendor\emitter_EventEmitter.js:135:10 in EventEmitter#emit at
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:414:4
in __callFunction at
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:113:6
in __guard$argument_0 at
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:365:10
in __guard at
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:112:4
in callFunctionReturnFlushedQueue

By reviewing UserInfoProvider context value:
let contextData = {
loginUser: loginUser,
logoutUser: logoutUser,
isLoggedIn: isLoggedIn,
errorMessage: errorMessage,
userProfile: userProfile,
getHistories: getHistories,
};
updateLocation function not available and you can't access.
You need to use useUserInfo to consume UserInfoProvider value.

Related

Multiple useEffect in react-native to achieve mentioned functionality

I need help with the async nature of Async storage and axios api. Here's the functionality that I am trying to achieve ->
send request to two separate api to get some data.
display that data on the screen with some additional text
api request are authenticated so a token is passed as Authentication Header
I have attached the current implementation, I am having the a number of errors in this
Errors:
Login_token not set in state after fetching from Async Storage.
Data not set in state after api call
both resulting in either failed api calls or undefined state errors on render
This is my code.
import React, { FunctionComponent, useEffect, useCallback, useState} from 'react';
import { StyleSheet, View} from 'react-native';
// chat
import { GiftedChat } from 'react-native-gifted-chat';
// navigation
import { RootStackParamList } from '../../navigators/RootStack';
import { StackScreenProps } from '#react-navigation/stack';
export type Props = StackScreenProps<RootStackParamList, "Chat">;
// api
import { Convo_details, Send_Msg, List_Msg, Expert_Public_Profile } from '../../api/UserApi';
import Spinner from 'react-native-loading-spinner-overlay';
import AsyncStorage from '#react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';
const Chat: FunctionComponent<Props> = ({ navigation, route, ...props }) => {
// console.log(props.route.params);
const [login_token, setlogin_token] = useState('')
const [conversation_id, setconversation_id] = useState('')
const [conversation_details, setconversation_details] = useState({})
const [currentuser, setcurrentuser] = useState({})
const [loading, setLoading] = useState(false);
const [expertuid, setexpertuid] = useState('')
const [ExpertProfile, setExpertProfile] = useState({})
const [messages, setMessages] = useState([]);
useEffect(() => {
getlogintoken()
console.log("####################################","getlogintoken");
}, [])
/* conversationid */
useEffect(() => {
if (route.params != null) {
setconversation_id(route.params[0])
}
console.log("####################################","conversation id");
}, [])
/* expert uid */
useEffect(() => {
if (route.params != null) {
setexpertuid(route.params[1])
}
console.log("####################################","expert uid");
}, [])
/* expert public profile */
useEffect(() => {
getexpertpublicprofile()
getConvo_details()
console.log("####################################","convo_details");
}, [])
useEffect(() => {
// get current user
AsyncStorage.getItem("currentuser").then(res => {
if (res != null) setcurrentuser(res)
else alert("Current user not found")
})
console.log("####################################","current user");
}, [])
// set welcome msg
useEffect(() => {
if (Object.keys(conversation_details).length != 0 && Object.keys(ExpertProfile).length != 0)
setwelcomemsg()
}, [])
const onSend = useCallback(async (messages = []) => {
// console.log(messages[0].text);
setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
const data = {
conversation_id: "f98d6851-a713-4f58-9118-77a779ff175f",//conversation_id,
message_type: "TEXT",
body: messages[0].text
}
const res: any = await Send_Msg(data, login_token)
.catch(error => {
alert(`Send_Msg -> ${error}`)
console.log(error);
return
})
if (res.status == 200) {
console.log(res.data);
} else console.log(res);
}, [])
const getexpertpublicprofile = async () => {
setLoading(true)
const res: any = await Expert_Public_Profile(expertuid, login_token)
.catch(error => {
setLoading(false)
console.log("Expert public profile ->");
alert(`Expert public profile ->${error.message}`)
console.log(error);
return
})
setLoading(false)
if (res.status === 200) setExpertProfile(res.data)
else {
alert(`get expert public profile${res.data.message}`)
console.log("getexpertpublicprofile -->");
console.log(res.data);
}
}
const getlogintoken = () => {
AsyncStorage.getItem("login_token").then(res => {
if (res != null) {
setLoading(false)
setlogin_token(res)
}
else alert("No login token found")
})
}
const getConvo_details = async () => {
setLoading(true)
const res: any = await Convo_details(conversation_id, login_token)
.catch(error => {
setLoading(false)
alert(`Convo_details-->${error.message}`)
console.log("Convo_details -->");
console.log(error);
return
})
setLoading(false)
if (res.status === 200) setconversation_details(res.data)
else {
alert(`get convo details-> ${res.data.message}`)
console.log("getConvo_details -->");
console.log(res.data);
}
}
const setwelcomemsg = () => {
try {
let user = JSON.parse(currentuser)
let messages = [
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `About Me - ${ExpertProfile.bio}`,
user: {
_id: conversation_details.recipient.user_uid,
}
},
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `My name is ${conversation_details.recipient.name}`,
user: {
_id: conversation_details.recipient.user_uid,
}
},
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `Hi ${user.full_name}`,
user: {
_id: conversation_details.recipient.user_uid,
}
}]
setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
} catch (error) {
console.log("try -> set welcome msg");
console.log(error);
return
}
}
return (
<View style={styles.maincontainer}>
<Spinner
visible={loading}
textContent={'Loading...'}
textStyle={{ color: '#FFF' }}
/>
<GiftedChat
messages={messages}
onSend={messages => onSend(messages)}
user={{
_id: currentuser.user_uid,
}}
isTyping={false}
scrollToBottom={true}
showAvatarForEveryMessage={true}
renderAvatar={() => null}
/>
</View>
);
}
export default Chat;
const styles = StyleSheet.create({
maincontainer: {
flex: 1,
},
});
When axios returns, it usually give the response as res.data, so in your case, try either res.data or res.data.yourToken (I'm not sure how it's your object).
Gurav,
As far as your code above, The api call's will trigger even before you get currentuser or loginToken. You have to handle the api call after getting the currentuser and loginToken. This can be gracefully handled with async, await.
example code:
useEffect(() => {
getData()
}, [])
useEffect(() => {
if(login_token && currentuser) {
//The api call goes here after you get the logintoken andcurrentuser.
// The above condition is just an example but will vary based on your requirements
}
}, [login_token, currentuser])
const getData = async () => {
await getlogintoken()
await getcurrentuser()
}
const getlogintoken = async () => {
await AsyncStorage.getItem("login_token").then(res => {
if (res != null) {
setLoading(false)
setlogin_token(res)
}
else alert("No login token found")
})
}
const getcurrentuser = async () => {
await AsyncStorage.getItem("currentuser").then(res => {
if (res != null) setcurrentuser(res)
else alert("Current user not found")
})
}

asyncstorage with useReducer does not save the values

i am new to reactnative, i was trying to build todo app using useReducer and asyncstorage but not able to achieve that, i have read every article and related questions i am able to do it using useState but did not got the result with useReducer.
Any help/suggestions will be appreciated. Thank You .
const MainScreen = () => {
const getData = async () => {
try {
const data = await AsyncStorage.getItem('itemlist');
return (output = JSON.parse(data));
} catch (e) {
}
};
React.useEffect(() => {
getData();
}, []);
const [text, setText] = React.useState('');// for textinput
const { dispatch } = useContext(NotesContext);
const handleSubmit = async () => {
try {
const output = JSON.stringify(state);
await AsyncStorage.setItem('itemlist', output);
} catch (error) {
console.log(error);
}
if (text) {
dispatch({ type: 'ADD_TODO', payload: text });
}
setText('');
};
//this is my reducer function below
export const TodoReducer = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return state.concat({
task: action.payload,
id: uuid.v4(),
complete: false,
});
case 'DELETE_TODO':
return state.filter((todo) => todo.id !== action.payload);
default:
throw new Error();
}
};

EXPO-AV not playing sound and not throwing any errors

I am trying to load the sound which i retrieve from my own API into the EXPO AV createAsync function:
const PlayerWidget: React.FC = () => {
const [song, setSong] = useState(null);
const [sound, setSound] = useState<Sound | null>(null);
const [isPlaying, setIsPlaying] = useState<boolean>(true);
const [liked, setLiked] = useState<boolean>(false);
const [duration, setDuration] = useState<number | null>(null);
const [position, setPosition] = useState<number | null>(null);
const { songId } = useContext(AppContext);
const { data, error } = useQuery(SongQuery, {
variables: { _id: songId },
});
useEffect(() => {
if (data && data.song) {
setSong(data.song);
}
}, [data]);
useEffect(() => {
if (song) {
playCurrentSong();
}
}, [song]);
const playCurrentSong = async () => {
if (sound) {
await sound.unloadAsync();
}
const { sound: newSound } = await Sound.createAsync(
{ uri: song.soundUri },
{ shouldPlay: isPlaying }
);
console.log("sound" + newSound);
setSound(newSound);
};
const onPlayPausePress = async () => {
if (!sound) {
console.log("no sound");
return;
}
if (isPlaying) {
await sound.pauseAsync();
} else {
await sound.playAsync();
}
};
const onLikeSong = async () => {
try {
setLiked(true);
} catch (e) {
console.log(e);
}
};
const getProgress = () => {
if (sound === null || duration === null || position === null) {
return 0;
}
return (position / duration) * 100;
};
const onPlaybackStatusUpdate = (status) => {
setIsPlaying(status.isPlaying);
setDuration(status.durationMillis);
setPosition(status.positionMillis);
};
}
Weirdly enough, the log after the function does not even work, it is never logged. I don't get any errors though, making it quite hard to debug this where it goes wrong, the URI is working and pointing towards an mp3 file, and the state is set correctly. Any pointers how i could debug this further?

React-native: How to change the audio speed in expo-av

I'm having trouble changing the prop: 'rate' to change the speed of the audio being played.
I'm using expo-av (https://docs.expo.dev/versions/latest/sdk/av/).
Here's my code:
import {Text, View, Alert } from 'react-native'
import * as MediaLibrary from 'expo-media-library';
import { DataProvider } from 'recyclerlistview';
import {Audio} from 'expo-av';
import { play, pause, resume, playNext } from "../misc/AudioController";
export const AudioContext = createContext()
export class AudioProvider extends Component {
constructor(props) {
super(props);
this.state = {
audioFiles: [],
permissionError: false,
dataProvider: new DataProvider((r1, r2) => r1 !== r2),
playbackObj: null,
soundObj: null,
currentAudio: {},
isPlaying: false,
currentAudioIndex: null,
playbackPosition: null,
playbackDuration: null,
rate: 2.0,
};
this.totalAudioCount = 0;
}
permissionAlert = () => {
Alert.alert("Permission Required", "This app needs to read audio files", [
{ text: "I am ready", onPress: () => this.getPermission() },
{
text: "cancel",
onPress: () => this.permissionAlert(),
},
]);
};
getAudioFiles = async () => {
const { dataProvider, audioFiles } = this.state;
let media = await MediaLibrary.getAssetsAsync({
mediaType: "audio",
});
media = await MediaLibrary.getAssetsAsync({
mediaType: "audio",
first: media.totalCount,
});
this.totalAudioCount = media.totalCount;
this.setState({
...this.state,
dataProvider: dataProvider.cloneWithRows([
...audioFiles,
...media.assets,
]),
audioFiles: [...audioFiles, ...media.assets],
});
};
loadPreviousAudio = async () => {
let previousAudio = await AsyncStorageLib.getItem("previousAudio");
let currentAudio;
let currentAudioIndex;
if (previousAudio === null) {
currentAudio = this.state.audioFiles[0];
currentAudioIndex = 0;
} else {
previousAudio = JSON.parse(previousAudio);
currentAudio = previousAudio.audio;
currentAudioIndex = previousAudio.index;
}
this.setState({ ...this.state, currentAudio, currentAudio });
};
getPermission = async () => {
// {
// "canAskAgain": true,
// "expires": "never",
// "granted": false,
// "status": "undetermined",
// }
const permission = await MediaLibrary.getPermissionsAsync();
if (permission.granted) {
this.getAudioFiles();
}
if (!permission.canAskAgain && !permission.granted) {
this.setState({ ...this.state, permissionError: true });
}
if (!permission.granted && permission.canAskAgain) {
const { status, canAskAgain } =
await MediaLibrary.requestPermissionsAsync();
if (status === "denied" && canAskAgain) {
this.permissionAlert();
}
if (status === "granted") {
this.getAudioFiles();
}
if (status === "denied" && !canAskAgain) {
this.setState({ ...this.state, permissionError: true });
}
}
};
onPlaybackStatusUpdate = async (playbackStatus) => {
console.log("hier");
if (playbackStatus.isLoaded && playbackStatus.isPlaying) {
this.updateState(this, {
playbackPosition: playbackStatus.positionMillis,
playbackDuration: playbackStatus.durationMillis,
});
}
if (playbackStatus.didJustFinish) {
const nextAudioIndex = this.state.currentAudioIndex + 1;
if (nextAudioIndex >= this.totalAudioCount) {
this.state.playbackObj.unloadAsync();
this.updateState(this, {
soundObj: null,
currentAudio: this.state.audioFiles[0],
isPlaying: false,
currentAudioIndex: 0,
playbackPosition: null,
playbackDuration: null,
});
}
const audio = this.state.audioFiles[nextAudioIndex];
const status = await playNext(this.state.playbackObj, audio.uri);
this.updateState(this, {
soundObj: status,
currentAudio: audio,
isPlaying: true,
currentAudioIndex: nextAudioIndex,
});
}
};
componentDidMount() {
this.getPermission();
if (this.state.playbackObj === null) {
this.setState({ ...this.state, playbackObj: new Audio.Sound(), });
}
}
updateState = (prevState, newState = {}) => {
this.setState({ ...prevState, ...newState });
};
render() {
const {
audioFiles,
dataProvider,
permissionError,
playbackObj,
soundObj,
currentAudio,
isPlaying,
currentAudioIndex,
playbackPosition,
playbackDuration,
rate,
} = this.state;
if (permissionError)
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>It looks like you haven't accepted the permission</Text>
</View>
);
return (
<AudioContext.Provider
value={{
audioFiles,
dataProvider,
playbackObj,
soundObj,
currentAudio,
isPlaying,
currentAudioIndex,
totalAudioCount: this.totalAudioCount,
playbackPosition,
playbackDuration,
rate,
updateState: this.updateState,
loadPreviousAudio: this.loadPreviousAudio,
onPlaybackStatusUpdate: this.onPlaybackStatusUpdate
}}
>
{this.props.children}
</AudioContext.Provider>
);
}
}
import {Component} from 'react';
import AsyncStorageLib from '#react-native-async-storage/async-storage';
export default AudioProvider;
and here's some more:
// play audio
// Import the react-native-sound module
import { PitchCorrectionQuality,shouldCorrectPitch, rate } from "expo-av/build/AV.types";
export const play = async (playbackObj, uri,) => {
try {
return await playbackObj.loadAsync(
{uri},
{shouldPlay: true},
);
} catch (error) {
console.log('error inside play helper method', error.message)
}
};
//pause
export const pause = async playbackObj => {
try {
// playbackObj.setRateAsync(rate = 2.0, shouldCorrectPitch = true, PitchCorrectionQuality= High);
return await playbackObj.setStatusAsync({
shouldPlay: false},
);
} catch (error) {
console.log('error inside pause helper method', error.message)
}
};
//resume
export const resume = async playbackObj => {
try {
return await playbackObj.playAsync(
);
} catch (error) {
console.log('error inside pause resume method', error.message)
}
};
//select next
export const playNext = async (playbackObj, uri) => {
try {
await playbackObj.stopAsync()
await playbackObj.unloadAsync();
return await play(playbackObj, uri);
} catch (error) {
console.log('error inside playNext helper method')
}
}
I've tried including 'rate: 2.0' inside this.state{audioFiles: [],
permissionError: false, etc.} but it didn't work.
Also I've tried doing: await playbackObj.setRateAsync() in the 2nd code snippet.
Any suggestions?
Nvm, I found the solution. Here's my updated code:
// play audio
// Import the react-native-sound module
import { PitchCorrectionQuality,shouldCorrectPitch, rate } from "expo-av/build/AV.types";
export const play = async (playbackObj, uri,) => {
try {
await playbackObj.loadAsync(
{uri},
{shouldPlay: true},
);
return await playbackObj.setStatusAsync({ rate: 0.9749090909 });
} catch (error) {
console.log('error inside play helper method', error.message)
}
};
//pause
export const pause = async playbackObj => {
try {
return await playbackObj.setStatusAsync({
shouldPlay: false,
rate: 0.9749090909,
});
} catch (error) {
console.log('error inside pause helper method', error.message)
}
};
//resume
export const resume = async playbackObj => {
try {
return await playbackObj.playAsync(
);
} catch (error) {
console.log('error inside pause resume method', error.message)
}
};
//select next
export const playNext = async (playbackObj, uri) => {
try {
await playbackObj.stopAsync()
await playbackObj.unloadAsync();
return await play(playbackObj, uri);
} catch (error) {
console.log('error inside playNext helper method')
}
}

Hash value null error in react-native hooks useEffect

the hash data I received using asyncStorage in my react native project is wrong. It actually works when I refresh the page. My request is probably running earlier than hash. However, I could not find a solution to this.
const [info, setInfo] = useState('');
const [hash, setHash] = useState(null);
const _retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('hash');
setHash(value)
} catch (error) {
// Error retrieving data
}
};
useEffect(() => {
_retrieveData()
setTimeout(() => {
console.log(hash) //
axios.get(apiUrl + 'loginInfo?hash=' + hash)
.then(response => {
setInfo(response.data.message);
console.log('res', response);
});
}, 1000);
}, []);
The _retriveData method should be inside of the useEffect.
const [info, setInfo] = useState('');
const [hash, setHash] = useState(null);
useEffect(() => {
const _retrieveData = async () => {
try {
const hash = await AsyncStorage.getItem('hash');
return hash
} catch (error) {
console.log('error',error);
// Error retrieving data
}
};
const hash = _retrieveData()
setTimeout(() => {
console.log(hash) //
axios.get(apiUrl + 'loginInfo?hash=' + hash)
.then(response => {
setInfo(response.data.message);
console.log('res', response);
});
}, 1000);
}, []);
I solved the problem by getting help from a friend.
const [info, setInfo] = useState({});
const [hash, setHash] = useState(null);
const _retrieveData = useCallback(async () => {
try {
const value = await AsyncStorage.getItem('hash');
setHash(value);
} catch (error) {
// Error retrieving data
}
}, []);
const getInfo = useCallback(async () => {
try {
const response = await axios.get(apiUrl + 'loginInfo?hash=' + hash);
setInfo(response.data.message)
} catch (e) {
console.log(e);
}
}, [hash]);
useEffect(() => {
if (!hash) {
_retrieveData();
}
}, [hash])
useEffect(() => {
if (hash) {
setTimeout(() => {
getInfo();
},500)
}
}, [hash, getInfo]);