I am building an Android app and I am struggling using the AsyncStorage. I want to create a function that takes a key as input and give me back the item. My problem is that when I call this function, it returns { _40: 0, _65: 0, _55: null, _72: null } instead the value I am looking for.
Here is my code :
renderList() {
async function save() {
await AsyncStorage.setItem('Title', 'hello');
}
async function fetch(key) {
const value = await AsyncStorage.getItem(key);
console.log(value) ; // Return hello
return value
}
save() ;
fetch() ;
const reponse = fetch() ;
console.log(reponse) ; // Return { _40: 0, _65: 0, _55: null, _72: null }
return (
<Text style={styles.noteElementTitle}> Aa </Text>
)
}
Edit :
I tried this :
async function getBody() {
await save();
const response = await fetch('Title');
console.log(response);
this.setstate({ title : response}) ;
}
getBody() ;
But I still get an error : TypeError: undefined is not a function (evaluating 'this.setstate({ title: response })')
What you're seeing is the Promise object returned by a function marked async. You need to either use await when calling the function, or treat the value as a promise and use then and catch. For example:
await save();
const response = await fetch();
console.log(response);
or
save()
.then(() => fetch())
.then(response => console.log(response));
Also, keep in mind that you should not be using async functions inside a render function. In your code above, you'll want to put the result of your fetch() function into component state.
Related
I am very new with the MergeMap method to combine multiple API requests. I have following and reading this tutorial how to do it.
https://levelup.gitconnected.com/handle-multiple-api-requests-in-angular-using-mergemap-and-forkjoin-to-avoid-nested-subscriptions-a20fb5040d0c
This is my code to get data from an API:
Service.ts
getPriceList(): Observable<Price[]> {
this.http.get<Price[]>(this.baseUrl).pipe(
map( priceId => {
const id = priceId[0];
this.priceId = id.id;
return id;
}),
mergeMap( Id=> this.http.get(this.baseUrl2 + /${Id.id})),
).subscribe( productPrices => {
this.productPrices = productPrices;
});
}
I need all the data from the first baseUrl, but I assign the Id to use it in my second api request. I call this method in home.ts like this:
this.dataService.getPriceList().subscribe(response => {
console.log(response);
this.priceListData = response;
There is no error when I call this method in the file.
The error is in the method from Service.ts
A function whose declared type is neither 'void' nor 'any' must return
a value.ts(2355)
I am using the return statement in the first api request.
I have tried this solution:
A function whose declared type is neither 'void' nor 'any' must return a value
Then I get the following error:
Type 'Subscription' is missing the following properties from type
'Observable<Crypto[]>': _isScalar, source, operator, lift, and 6
more.ts(2740)
How to use the MergeMap the right way in Angular 11 / ionic 6?
I think you should return something on getPriceList, which you weren't, and if you subscribe inside getPriceList there is no observable anymore to subscribe after that
getPriceList(): Observable<Price[]> {
return this.http
.get<Price[]>(this.baseUrl)
.pipe(
map(priceId => {
const id = priceId[0];
this.priceId = id.id;
return id;
}),
mergeMap(id => this.http.get(`this.baseUrl2${id.id}`))
)
}
and the call
this.dataService.getPriceList().subscribe(response => {
console.log(response);
this.priceListData = response;
});
I'm currently working with React native mobile application, on this process I use SQLite to store data locally within the phone the problem is I have assigned a variable getToken which need to be filled by the token I stored in SQLite DB. below is the method i tried and it always returns the default value.
function getTest() {
let getToken = 'ABC';
db.transaction(tx => {
tx.executeSql('SELECT * FROM Login', [], (tx, result) => {
getToken = result.rows.item(0).access_token;
});
});
return getToken;
}
The problem occurs because of transaction and executeSQL are async methods. Try using await or resolve a promise inside executeSQL callback. i solved this issue as follows
async function returnToken() {
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql('SELECT * FROM Login', [], (tx, result) => {
let accessToken = result.rows.item(0).access_token;
resolve(accessToken);
});
});
});
}
async function (config){
let token = await returnToken();
console.log('token', token);
}
I am new in react native and getting the bind value at index 1 is null when I am trying to get data from AsyncStorage in react-native below is my code.
Alert.alert(
'Info',
'React AsyncStorage',
[
{text: 'Get Data',onPress: () => this.getValue('name'),},
{text: 'Save Data', onPress: () => this.saveValue('name', 'abc'),}
],
{cancelable: false},
);
async saveValue(key:String, value:bool) {
AsyncStorage.setItem(key, value);
Alert.alert('Data', 'saving');
}
async getValue(key) {
// try {
// await AsyncStorage.getItem(Constant.SHOW_INTRO).then((value) =>
// console.log(`AsyncStorage GET for Constant.SHOW_INTRO: "${value}"`));
// } catch (error) {
// Alert.alert('Error', 'Error retrieving data');
// }
try {
const value = await AsyncStorage.getItem(key)
console.log(`AsyncStorage GET for "${key}": "${value}"`);
} catch (error) {
Alert.alert('Error', 'Error retrieving data');
}
}
Please help.
You can use this format:
setData = (value) => {
// if value is an Object use this: value = JSON.stringify(value)
// if value is a number use this: value = value.toString()
AsyncStorage.setItem('myKey', value, () => {
console.warn('Done!')
})
}
getData = () => {
AsyncStorage.getItem('myKey').then(storage => {
console.warn(storage)
}).catch(e => console.warn(e))
}
Then:
this.setData('sample text')
Edit:
AsyncStorage takes some time to fetch data so it returns a promise until the value is available. You have to call the then() function and get the value from there. Anything inside the then() function is called after the value is retrieved from storage.
Try doing it this way:
async getValue(key){
try {
const value = await AsyncStorage.getItem(key)
console.log(`AsyncStorage GET for "${key}": "${value}"`);
} catch (error) {
Alert.alert('Error', 'Error to retrieve data');
}
}
I am writing a cloud function for my project . its being last 12 hours that i am stuck with this error "Function returned undefined, expected Promise or value"
i have tried alot to remove it but not able to find how to solve it
exports.Notify = functions.database.ref('blood_share/Notifications/{user}/{notificationid}').onWrite((change, context) => {
const username=context.params.user;
const notifyid=context.params.notificationid;
const query = admin.database().ref("blood_share/Notifications").child(username).child(notifyid);
query.once('value').then(snapshot=>{
const event = snapshot.val();
const notificationMessage = event.messsage;
const token_id=event.reciever_appid;
console.log("message"+notificationMessage);
//create notification Json
const payLoad = {
notification:{
title: "New Request For Food",
body: "kuch b",
icon: "default"
}
};
return snapshot.val();
}).catch(error => {
console.error(error);
});
});
You are returning the value when the query.once('value') promises resolves.
To clarify this, look at this:
let a = 0;
asyncFunctionPromise.then(() => {
a = 1;
});
console.log(a); // Will print 0 instead of
Instead directly return the promise return query.once('value').then(.... or build your own with
return new Promise((resolve) => {
query.once('value').then(snapshot=>{
// do something
resolve(snapshot.val()); // To resolve the promise with snapshot.val()
});
})
you need to return the promise
return query.once('value').then(snapshot=>{
//....
Instead of return snapshot.val() which is a value, return a Promise
return Promise.resolve(snapshot.val());
I ran into a bug whenever I run my React Native app on an Android device (physical and emulator). Yet, no problem at all on iOS. These functions are supposed to scan the database table for user handles and return an object if the handle already exists.
This is what the error looks like:
TypeError: Cannot read property 'handle' of null
at exports.handler (/var/task/index.js:7:36)
I'm using React Native, AWS Lambda, and EXPO.
This code lives within dbfunctions.js on the front end.
export async function scanHandles(){
return new Promise((resolve, reject) => {
let { auth } = store.getState()
let reqBody = {
userId: auth.user.username,
handle: auth.handle_update,
}
let path = '/u/scan-handle'
let myInit = {
headers: { 'Content-Type': 'application/json' },
body: reqBody,
}
console.log('myInit', myInit)
console.log('handle', auth.handle_update)
API.get(apiName, path, myInit)
.then((resp) => {
// if false, then handle does not exist
// if true, then handle already exists
resolve(resp)
})
.catch((error) => {
console.warn('Scan Handle', error)
reject(error)
})
})
}
Console logging auth.handle_update does print out the expected string. myInit also prints out the expected object.
On the back end, I'm using this for my scan:
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient({ region: "us-west-1" });
exports.handler = (event, context, callback) => {
let e = JSON.parse(event.body);
var params = {
TableName: event.stageVariables.user,
FilterExpression: "handle = :handle",
ExpressionAttributeValues: { ":handle": e.handle }
};
docClient.scan(params, function(err, data) {
if (err) {
console.log("ERROR:", err);
let response = {
statusCode: err.statusCode,
headers: {},
body: JSON.stringify(err)
};
callback(response);
}
if (data.Count >= 1) {
// if user name exists
// call back handle exists response
let handleExistsResponse = {
statusCode: 200,
body: JSON.stringify({ Success: true })
};
callback(null, handleExistsResponse);
} else {
let response = {
statusCode: 200,
body: JSON.stringify({ Success: false })
};
callback(null, response);
}
});
};
Any idea as to why this would work on iOS and not Android?
EDIT:
Upon further testing, let e = JSON.parse(event.body) is returning null. So I console logged event and got a big ol object. Within this object, I found body and it's still null. So the body object isn't being passed it properly. Still confused about it working on iOS and not Android.
Did it!
Okay so API.get doesn't like body's being passed in. Instead, it wants a query parameter. So the lambda params looks like:
var params = {
TableName: event.stageVariables.user,
FilterExpression: "handle = :handle",
ExpressionAttributeValues: {
":handle": event["queryStringParameters"]["handle"]
}
};
And the front end function is:
export async function scanHandles(){
return new Promise((resolve, reject) => {
let { auth } = store.getState()
let handle = auth.handle_update
let path = `/u/scan-handle?handle=${handle}`
let myInit = {
headers: { 'Content-Type': 'application/json' },
}
API.get(apiName, path, myInit)
.then((resp) => {
// if false, then handle does not exist
// if true, then handle already exists
resolve(resp)
})
.catch((error) => {
console.warn('Scan Handle', error)
reject(error)
})
})
}
Works on both iOS and Android. Wonder why it wasn't working before?