How to parse data from AsyncStorage to <Text> - react-native

I am getting the following error when I get data from AsyncStorage:
Objects are not valid as a React child (found: object with keys {_40, _65, _55, _72})
async function setItem(key, value) {
try {
await AsyncStorage.setItem(key, value);
console.log(key, value);
return value;
} catch (error) {
// Handle errors here
}
}
async function getItem(item) {
try {
const value = await AsyncStorage.getItem(item);;
console.log(value);
return value;
} catch (error) {
// Handle errors here
}
}
setVar = setItem('username', 'Name');
getVar = getItem('username');
I am getting the error when outputting the result to:
<Text>{getVar}</Text>
When I check console I get the required output/everything is correct but I cannot render the text to the screen.
Any help or suggestions would be greatly appreciated.
Thanks.

Cross posting from https://forums.expo.io/t/how-to-parse-data-from-asyncstorage-to-text/3417/4
Ah, your function getItem is giving back a Promise, remember that async keyword automatically makes the function return Promise. Hence the error message, can’t put the Promise object in
Suggest you:
Put the string you’ll use in state:
state = {showThisText:''}
in render: {this.state.showThisText}
Then in async componentDidMount, get the data and do a this.setState({showThisText:YOUR_PULLED_STRING})

try it like this it will work,
setVar = await setItem('username', 'Name');
getVar = await getItem('username');
make both of your calling functions async too.

Related

Express Mongoose throw custom error on callbacks

I'm trying to throw some custom error classes from mongoose callbacks.
Here is a simple code
const Restaurant = require('../models/Restaurant')
const { InternalServerError, UnauthorizedError } = require('../errors/errors')
const checkRestaurantAuthorization = async (token) => {
const restaurant = Restaurant.findOne({ 'token': token }, function (error, result) {
if (error) throw new InternalServerError()
else if (!result) throw new UnauthorizedError()
else return token
})
}
In my code checkRestaurantAuthorization is called by a simple middleware like
const restaurantMidlleware = async (req, res, next) => {
console.log('Request Type:', req.method);
try {
token = await checkRestaurantAuthorization('invalid_token')
next()
} catch (error) {
next(error)
}
}
Now if a restaurant instance with the given token is not found, the app crashes with throw er; // Unhandled 'error' event. From my testing it seems that executions stops when throw new UnauthorizedError() is called and I'm unable to identify the issue.
Here is also an example of a custom defined error if it's useful
class UnauthorizedError extends Error {
constructor(message) {
super(message)
this.name = 'Unauthorized request'
this.code = 403
Error.captureStackTrace(this, UnauthorizedError)
}
}
What am I missing?
have you tried putting your first block in 'try-catch' block?
The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate.
you can change code to promise or async-await
another source of the problem could be the fact that your are using async and callback in one function try to omit async then use it again
And there is no point in writing 'const restaurant =' in
const restaurant = Restaurant.findOne
since every found restaurant will be saved in callback's result variable
try this
function checkRestaurantAuthorization(token){
return new Promise(async(resolve, reject)=>{
try {
const restaurant = await Restaurant.findOne({ 'token': token });
if (!restaurant)
return reject(new UnauthorizedError())
else
return resolve(token)
}catch(error){
return reject(new InternalServerError())
}
})}
Even better approach would be using only async function with try-catch instead of returning a promise or any callback

AsyncStorage functions just producing garbage in react native

So I implemented this code in a file from the react native docs.
class Storage {
//store data in 'key'
store = async (key, data) => {
try {
await AsyncStorage.setItem(key, data);
} catch (error) {
// Error saving data
console.log(error.message);
}
};
retrieve = async (key) => {
try {
const value = await AsyncStorage.getItem(key);
if (value !== null) {
// We have data!!
console.log(value);
}
} catch (error) {
// Error retrieving data
console.log(error.message);
}
};
}
And this in other I want to use to actually store and retrieve the variables:
strg.store('test', 'testing');
testing = strg.retrieve('test');
I kept getting an error but then looking it up here I figured out my storage output was an object and not a string as I expected. So I used JSON.stringify(***) and this gibberish came out instead of a "testing".
{"_40":0, "_65":0, "_55":null,"_72":null}
edit: I figure out how to use the console to debug and I found out the 'testing' was inside the promise object that comes out of my function. I read a little about async functions and now I want to know how do I extract the values from the promises?
This happened because you are using AsyncStorage - an asynchronous storage system. You have to wait until it done retrieve data from storage to get the proper data.
I think there are two correct ways to get data from your implementation:
Use async with your container function name & await with your function called
async function getData() {
....
let data = await strg.retrieve('test');
console.log("data", data);
}
or simple use .then():
strg.retrieve('test').then((data) => {
console.log("data", data);
// Handle retrieved data
});
Hope that help. :)
This is how i did it and it works like a charm
import { AsyncStorage } from 'react-native';
module.exports = {
retrieve: async (value) => {
try {
let data = await AsyncStorage.getItem(value);
return data;
} catch (err) {
return err;
}
},
store: async (key, value) => {
try {
// stringify the value since value can only be string.
if (typeof (value) === 'object')
value = JSON.stringify(value)
return await AsyncStorage.setItem(key, value);
} catch (err) {
console.log(err)
return err;
}
}
}
Your store and retrieve functions are asyn so you have to use await until the actual task is complete.
So the code should be like below.
await strg.store('test', 'testing');
const testing = await strg.retrieve('test');
The garbage value is a promise so it will be something like the object you got.
If you return value like this you will retrieve it from outside.
const value = await AsyncStorage.getItem(key);
if (value !== null) {
// We have data!!
console.log(value);
return value;
}

React Native AsyncStorage: using await and async

I'm trying to get all keys from my AsyncStorage database and then filter them in another function, can't seem to get it to wait until AsyncStorage has returned the data?
This function returns the keys in an array:
DATABASE_getAllCoffeeEntries = () => {
AsyncStorage.getAllKeys((err, keys) => {})
.then(keys => {
AsyncStorage.multiGet(keys, (error, items) => {
return items;
}).then(items => {
return items; // array of items is returned
});
});
}
and this function is meant to call the function above then wait for the result then filter down the data.
somefunc = async () => {
var items = await DATABASE_getAllCoffeeEntries();
var someItems = items.filter(function (result, i, item) {
// do filtering stuff
return item;
});
// do something with filtered items
}
Have tried a lot on here but can't get my head around it... any help would be great, thanks.
You need to actually return something from your DATABASE_getAllCoffeeEntries
You could do something like this.
First we wrap your call inside a promise. Which will resolve if we get all the items from AsyncStorage or reject if there is a problem.
Make sure that our calls to AsyncStorage are inside a try/catch. await calls can throw so we need to make sure that we handle any errors.
Use async/await when getting the items from AsyncStorage as this gets ride of the callbacks that are trapping the responses from AsyncStorage. It also can make your code easier to read
Here is the refactor
DATABASE_getAllCoffeeEntries = () => {
return new Promise( async (resolve, reject) => {
try {
let keys = await AsyncStorage.getAllKeys();
let items = await AsyncStorage.multiGet(keys)
resolve(items)
} catch (error) {
reject(new Error('Error getting items from AsyncStorage: ' + error.message))
}
});
}
Then we can call the function like this, though we will have to wrap it in a try/catch as it can throw.
somefunc = async () => {
try {
var items = await this.DATABASE_getAllCoffeeEntries();
var someItems = items.filter(function (result, i, item) {
// do filtering stuff
return item;
});
// do something with filtered items
} catch (error) {
// do something with your error
}
}

React-native sync storage solution

In native iOS code, I could use the NSUserDefaults to store and fetch data, which are sync operations. In react-native the offer is to use AsyncStorage, but I need a solution for sync storing, like NSUserDefaults.
I'm gonna use the result of data fetching to determine which screen to show, but since it's async I always get undefined when trying to fetch the persisted data.
after calling
AsyncStorage.getItem('#MySuperStore:key');
react-native will call native function dependent on your platform in other thread
then it will return a promise to resolve it
,so if call like this
let value = AsyncStorage.getItem('#MySuperStore:key');
value ++;
your value is not valid cause it data will be available later
the correct way to do is :
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
if (value !== null){
// We have data!!
console.log(value);
}
} catch (error) {
// Error retrieving data
}
other way of doing this is
try {
AsyncStorage.getItem('#MySuperStore:key',(value )=>{
if (value !== null){
// We have data!!
console.log(value);
}});
} catch (error) {
// Error retrieving data
}
you could make it asynchronous for example
getData = async () => {
const value = await AsyncStorage.getItem('Yourkey');
this.setState({key: value})
}

React Native AsyncStorage: Accessing Value from Promise Object

When I use AsyncStorage.getItem() to retrieve the value (an email address) of a specified key, it returns a Promise object as indicated in the documentation. The value appears in object like so:
{
_45: 0
_54: null
_65: "testuser#test.com"
_81: 1
}
Can I reliably access this value by calling obj._65 or is there another way to accomplish this?
AsyncStorage return a promise. you can use .then for get value
exemple:
AsyncStorage.getItem('key').then((keyValue) => {
console.log(keyValue) //Display key value
}, (error) => {
console.log(error) //Display error
});
Looking at the docs you should be able to do this reliably to retrieve data from your async storage object.:
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
if (value !== null){
// We have data!!
console.log(value._65);
}
} catch (error) {
// Error retrieving data
}
you must use this within a function that is async however or you will get a runtime exception.