React > expo > Axio > Async do not wait for response - reactjs

I am a real dummy on expo and react.
I am trying to fetch infos API using AXIO.
My problem is that before the API request is finish, expo is asking for a return statement.
Here is my code :
const sendGetRequest = async () => {
try {
const resp = await axios.get(uri, {
auth: {
username: '*****',
password: '****'
}})
console.log(resp.data);
return (
<View style={styles.container}>
<Text style={styles.title}>Action</Text>
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
<Text>
Order ID: {resp.data.id}
Nom client: {resp.data.billing.first_name} {resp.data.billing.last_name}
</Text>
<EditScreenInfo path="/screens/TabTwoScreen.tsx" />
</View>
);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
sendGetRequest();
ANd I get this error :
" Nothing was return from render "
I guess that the await is not really awaiting the result of the async..
Can you help me to see where is my mistake???
Thanks you so much..
Regards,
Pierre

Pierre, try to add await before calling sendGetRequest();
Like this:
await sendGetRequest();

ok I found the solution to my problem.
I spent couple of usefull minutes to read more about promises and callbacks.
I was wrong thinking that a promise will hold the code until it get a response. When u understand that a promise send a callback once realized the right code is as following :
// Creating a "DOM listener" -> sorry about vocabulary
const [myText, setMyText] = useState("My Original Text");
// Creating the async/awaiting function
const sendGetRequest = async () => {
try {
var resp = await axios.get(uri, {
auth: {
username: '*******',
password: '*******'
}});
await setMyText('Nom du client:'+ resp.data.billing.first_name);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
sendGetRequest();
// AND RETURN THE HTML AS FOLLOW
<View>
<Text onPress = {() => setMyText("My Changed Text")}>
{myText}
</Text>
</View>

Related

React Native HealthKit getDailyStepCountSamples returning undefined or empty array

I'm using react-native-health to create an app to read daily step counts. I have manually added steps on the simulator Health app and the data source is showing my app and all the Health permissions are on but when I try to getDailyStepCountSamples, I get an empty array.
Also, another issue I have is that I need to initiate HealthKit each time before getting the empty array otherwise I get 'undefined'. Once I initiate HealthKit again, it will return 'undefined' AND log 'Steps: []'. Is there something wrong with my code?
import AppleHealthKit from 'react-native-health';
export function useHealthKit({
init = false,
steps = false,
}) {
const PERMS = AppleHealthKit.Constants.Permissions;
const initiate = () => {
let permissions = {
permissions: {
read: [
PERMS.StepCount,
],
},
};
AppleHealthKit.initHealthKit(permissions, (err, results) => {
if (err) {
console.log(err);
} else {
console.log('Initialized!', results),
}
});
};
const getSteps = () => {
let stepOptions = {
startDate: new Date(2021, 1, 1).toISOString(),
};
AppleHealthKit.getDailyStepCountSamples(
stepOptions,
(err, results) => {
if (err) {
return;
}
console.log('Steps: ', results);
},
);
};
init && initiate();
steps && getSteps();
}
I call this by doing the following:
const SomeView = () => {
<View>
<Button onPress={() => useHealthKit({init: true})>
<Text>Initiate HealthKit</Text>
</Button>
<Button onPress={() => console.log(useHealthKit({steps: true}))>
<Text>Console.log steps</Text>
</Button>
</View>
};
I've been trying to do something very similar all afternoon and getting the same result as you.
What fixed it for me was using this bizarre trick from one of the github threads
Basically you need to change your start date to one month earlier than you want to sample so in your case this would be 01/12/2020.
The original poster says this is caused by an issue in the C code.
I also set variables for includeManuallyAdded: true and period: 1444 in my options variable
Worked for me, hopefully it will for you!

How to update state of messages in react-native-gifted-chat?

I relying on API calls for sending messages using react-native-gifted-chat in a react native app, I want the flow to be like when the user clicks on the send button it should have the state as pending:true and when the API call is a success I want it to have it as pending:false,sent:true I can achieve the first part but even when the API call is a success it does not update the state. Below is my implementation of it, I am trying to follow solution posted [here][1] but I think something is wrong with my implementation, Please let me know if any clarification is required.
function SmsConversations({ route }) {
const onSend = useCallback((messages = []) => {
const [messageToSend] = messages;
messageToSend.pending = true;
sendSMS(toNumber, fromNumber, messageToSend.text)
.then((res) => {
messageToSend.pending = false;
messageToSend.sent = true;
})
.catch((err) => (messageToSend.pending = true))
.done();
setMessages((previousMessages) =>
GiftedChat.append(previousMessages, messageToSend)
);
}, []);
return (
<GiftedChat
messages={messages}
onSend={(messages) => onSend(messages)}
user={{
_id: 1,
}}
/>
);
}
Also if the API is errored is there a way to handle it using react-native-gifted-chat, like failed or something?

How to properly fetch data from async storage in react native?

I am attempting to load and retrieve local data through asynchronous storage. I've laid out the current set up on a page, but am unable to retrieve data. Data is definitely saved as I receive a notification about it once I click store data. But when I proceed to call data it returns a null value. What am I doing something wrong here?
const STORAGE_KEY = '#save_enableauto'
state={
enableAuto:false
}
_storeData = async enableAuto => {
try {
let x = toString(enableAuto);
await AsyncStorage.setItem(STORAGE_KEY, x)
alert('Data successfully saved!')
//this.setState({ enableAuto: x })
} catch (e) {
console.log(e)
alert('Failed to save name.')
}
}
_retrieveData = async () => {
console.log('trying to call data')
try {
const enableAuto = await AsyncStorage.getItem('STORAGE_KEY');
console.log(enableAuto)
if (enableAuto !== null) {
// We have data!!
console.log(enableAuto);
}
} catch (error) {
alert('failed to load previous settings.')
// Error retrieving data
}
};
...
<Button title={'Store Data'} onPress={() => this._storeData(this.state.enableAuto)}/>
<Button title={'call Data'} onPress={() => this._retrieveData()}/>
</View>
<View>
<CheckBox
value={this.state.enableAuto}
onValueChange={() => this.setState({ checked: !this.state.enableAuto })}
/>
The error above is while you are storing, you are setting :
await AsyncStorage.setItem(STORAGE_KEY, x)
and here STORAGE_KEY refers to value #save_enableauto
But while you are retrieving data
const enableAuto = await AsyncStorage.getItem('STORAGE_KEY');
you are giving 'STORAGE_KEY' as string , so that means its refering 'STORAGE_KEY' and it doesnt have any stored value. Try this
const enableAuto = await AsyncStorage.getItem(STORAGE_KEY);
Hope it helps. feel free for doubts

State change detected only when screen is tapped

I have a few TouchOpacity components which fire a function when pressed. This function retrieves data and then sets state.
const Summary = () => {
const [timeSpan, setTimeSpan] = useState('Day');
const [derivedData, setDerivedData] = useState({
chartTimeSpan: 'Day',
sales: [],
totalSales: 0,
orders: 0,
logins: 0,
});
const _fetchSummary = async (timeSpan) => {
console.log(`_fetchSummary HIT : ${timeSpan}`);
try {
const res = await axios.get(`/summary/${timeSpan.toLowerCase()}`);
const { loginCount, orderQty, sales, totalSales } = res.data;
await setDerivedData({
chartTimeSpan: timeSpan,
sales,
totalSales,
orders: orderQty,
logins: loginCount,
});
await setTimeSpan(timeSpan);
console.log(timeSpan, loginCount, orderQty, sales, totalSales);
} catch (err) {
console.log(err);
}
};
const _switchTimeSpan = (newTimeSpan) => {
console.log(`TimeSpan : ${timeSpan}`);
console.log(`NewTimeSpan : ${newTimeSpan}`);
if (timeSpan !== newTimeSpan) {
_fetchSummary(newTimeSpan);
}
};
const { chartTimeSpan, sales, totalSales, orders, logins } = derivedData;
console.log(derivedData);
return (
<>
<TouchableOpacity onPress={() => _switchTimeSpan('Day')}>
<Text style={dropDownItemStyle}>Day</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => _switchTimeSpan('Week')}>
<Text style={dropDownItemStyle}>Week</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => _switchTimeSpan('Month')}>
<Text style={dropDownItemStyle}>Month</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => _switchTimeSpan('Year')}>
<Text style={dropDownItemStyle}>Year</Text>
</TouchableOpacity>
</>
);
};
Everything works fine. The data gets fetched when i click the buttons too. However state doesn't get updated after the data is fetched. I know this because console.log(derivedData); just above the return statement doesn't run. When i tap anywhere on the screen the console.log(derivedData); gives the expected output. Note that i have not set any function which detects this event when i touch the screen.
I have used the derivedData in some other components but did not include those for simplicity sake.
The console.log(derivedData) will be run, when the components need to be rerendered. This depends on the injected state and props variables. Since state variables are not used in JSX, there is no need to rerender the component and log the new derivedData.
You could bypass this by using import { useEffect } from 'react'. Try to log derived data with:
useEffect(() => {
console.log(derivedData);
});
This issue was caused because I have included the following lines of code in App.js file.
XMLHttpRequest = GLOBAL.originalXMLHttpRequest
? GLOBAL.originalXMLHttpRequest
: GLOBAL.XMLHttpRequest;
// fetch logger
global._fetch = fetch;
global.fetch = (uri, options, ...args) => (global._fetch(uri, options, ...args)
.then((response) => {
console.log('Fetch', { request: { uri, options, ...args }, response });
return response;
}));
The above code allows to detect the network requests. I don't know why but although the above code shows the network requests it also delays the data passed from requests to go into the component unless the screen is tapped.
Commenting out the above lines in production lets the code work as it should.

Unable to pass params successfully to another .js file/screen

I'm trying to pass params from one screen to another screen using react-navigation, the problem I'm encountering is that when I console.log the param itself, the console returns 'undefined'. I can't seem to pinpoint what I'm doing wrong exactly. Any help or guidance would be much appreciated.
I tried the following, with no success:
-this.props.navigation.getParam('biometryStatus')
-this.props.navigation.state.params('biometryStatus')
This is my AuthenticationEnroll screen where my param is being initialised as the state of the component:
export default class AuthenticationEnroll extends Component {
constructor() {
super()
this.state = {
biometryType: null
};
}
async _clickHandler() {
if (TouchID.isSupported()){
console.log('TouchID is supported');
return TouchID.authenticate()
.then(success => {
AlertIOS.alert('Authenticated Successfuly');
this.setState({biometryType: true })
this.props.navigation.navigate('OnboardingLast', {
pin: this.props.pin,
biometryStatus: this.state.biometryType,
});
})
.catch(error => {
console.log(error)
AlertIOS.alert(error.message);
});
} else {
this.setState({biometryType: false });
console.log('TouchID is not supported');
// AlertIOS.alert('TouchID is not supported in this device');
}
}
_navigateOnboardingLast() {
this.props.navigation.navigate('OnboardingLast', {pin: this.props.pin})
}
render () {
return (
<View style={{flex: 1}}>
<Slide
icon='fingerprint'
headline='Secure authentication'
subhead='To make sure you are the one using this app we use authentication using your fingerprints.'
buttonIcon='arrow-right'
buttonText='ENROLL'
buttonAction={() => this._clickHandler()}
linkText={'Skip for now.'}
linkAction={() => this._navigateOnboardingLast()}
slideMaxCount={4}
slideCount={2}
subWidth={{width: 220}}
/>
</View>
)
}
}
And this is my OnboardingLast Screen where my param is being passed down and printed through console.log:
class OnboardingLast extends Component {
async _createTokenAndGo () {
let apiClient = await this._createToken(this.props.pin)
this.props.setClient(apiClient)
AsyncStorage.setItem('openInApp', 'true')
const { navigation } = this.props;
const biometryStatus = navigation.getParam('biometryStatus', this.props.biometryStatus);
console.log(biometryStatus);
resetRouteTo(this.props.navigation, 'Home')
}
/**
* Gets a new token from the server and saves it locally
*/
async _createToken (pin) {
const tempApi = new ApiClient()
let token = await tempApi.createToken(pin)
console.log('saving token: ' + token)
AsyncStorage.setItem('apiToken', token)
return new ApiClient(token, this.props.navigation)
}
render () {
return (
<View style={{flex: 1}}>
<Slide
icon='checkbox-marked-circle-outline'
headline={'You\'re all set up!'}
subhead='Feel free to start using MyUros.'
buttonIcon='arrow-right'
buttonText='BEGIN'
buttonAction={() => this._createTokenAndGo()}
slideMaxCount={4}
slideCount={3}
/>
</View>
)
}
}
Expected Result is that console.log(biometryStatus); returns 'true' or 'false', however it returns 'undefined'.
Since setState is asynchron, you send null (declared in your constructor) to your next page. By doing so, you will send true:
this.setState({ biometryType: true })
this.props.navigation.navigate('OnboardingLast', {
pin: this.props.pin,
biometryStatus: true,
});
You could also do this, since setState can take a callback as param:
this.setState({ biometryType: true }, () => {
this.props.navigation.navigate('OnboardingLast', {
pin: this.props.pin,
biometryStatus: true,
});
})
In your second page this.props.biometryStatus is undefined.
The second argument of getParam is the default value. You should change it like that
const biometryStatus = navigation.getParam('biometryStatus', false);

Resources