Convert variable stored in AsyncStorage then state to Number - react-native

How can I convert an AsyncStorage stored number (stored as a string) to a Number in react native (I am using Expo).
It works converting the string to a number like this:
myNum = Number('3'); // THIS WORKS
But this does not work:
myNum = Number(this.state.myStateNum); // This does not work, returns zero
myNum = Math.floor(this.state.myStateNum); // This does not work, returns zero
I am getting my variable from AsyncStorage and then storing as a state but I can't figure out why I can't convert it to a number.
If it helps this is how I set using async:
async function setItem(key, value) {
try {
await AsyncStorage.setItem(key, value);
console.log(key, value);
return value;
} catch (error) {
}
}
setVar = setItem('myStateNum', '3');
This is how I get using async:
async componentWillMount() {
const myStateNumGet = await AsyncStorage.getItem('myStateNum');
if (myStateNumGet) {
this.setState({ myStateNum: myStateNumGet });
} else {
this.setState({ myStateNum: false });
}
}
Any suggestions/help would be great.

Try this...
myNum = parseInt(this.state.myStateNum);
You can try other methods too, but the above should work for you...
https://coderwall.com/p/5tlhmw/converting-strings-to-number-in-javascript-pitfalls

This is because ASyncStorage.getItem() returns a Promise object, not the string that you are expecting.
You can find some more info about that here: https://facebook.github.io/react-native/releases/0.23/docs/asyncstorage.html
In terms of your problem, i'd structure your code to accept a callback to getItem, that way you can ensure a returned value before you do your computation. The code would look something like this.
AsyncStorage.getItem("myStateNum").then((result) => {
console.log(result);
this.setState({myStateEnum: result});
}).done();
You could also try using .value to get your result, eg let myStateNum = result.value. Am fairly rusty on the subject but these methods should be able to help you
Let me know if this helps.

this is a duplicate of the question here https://forums.expo.io/t/convert-variable-stored-in-asyncstorage-then-state-to-number/3430

Related

how to use expo-sqlite execute sql with typescript?

Hi all I want to use expo-sqlite to transaction object to execute an sql statement.
However, I got a problem in define the return value of the error function.
Here is the example code:
tx.executeSql(
// sql statement (ok)
"...",
// input arguments (ok)
[...],
// success case: since I use it in a promise, so I use: resolve(...) (ok)
() => {
resolve()
},
// failed case: I want to reject it, use reject()
// But I got an Error here! (Wrong!!!)
// Here ask me to return a boolean value, but how??? true or false???
(_, err) => {
reject(err) // not enough???
}
)
From the type definition file, I know, I need to return a boolean value for the error callback function, but which one? true or false???
Do you have some idea how to do it???
PS. Here is official doc about the expo-sqlite: https://docs.expo.io/versions/latest/sdk/sqlite/
I don't know why the error callback function does need a return type of boolean. Since we resolve/reject the promise anyways I think we can savely ignore the return type.
Below you can find my typescript synchronous example:
export const fetchTypeSaveSql = async <T>(sqlStatement: string, args: any[] | undefined): Promise<T[]> => {
return new Promise((resolve) => {
db.transaction(tx => {
tx.executeSql(
sqlStatement, args,
(_, result) => {
resolve(Array.from(result.rows as any) as T[])
},
(_, error): boolean => {
console.warn(error)
resolve([])
return false
})
})
})
}
The return type of SQLStatementErrorCallback is boolean (and not void) because it's used to indicate whether the error was handled or not.
If the error is handled (ie return true), the whole transaction doesn't fail. If it's not handled (ie return false), then it does. You should only return true if you've been able to suitably recover from the error.
Remember that executeSql is only used within a transaction (which is created via db.transaction or db.readTransaction). A transaction accepts it's own success and error callbacks.
You can check the this in the source code by working backwards from this: https://github.com/nolanlawson/node-websql/blob/7b45bf108a9cffb1c7e16b9a7dfec47be8361850/lib/websql/WebSQLTransaction.js#L64-L68
if (batchTask.sqlErrorCallback(self, res.error)) {
// user didn't handle the error
self._error = res.error;
return onDone();
}

How to render text only after a Promise has been resolved in React Native?

I am trying to dynamically translate some text to be displayed when a user clicks on the translate button, but I can't get it to save my values outside of the Promise. I haven't worked much with Promises and every example only shows console.log, rather than saving values outside of the Promise. I don't really understand how they work. Here is (most of) the code I am trying to fix:
constructor(props) {
super(props);
this.state = {
dynamicTranslate: this.props.dynamicTranslate,
};
}
// I've tried this method as both sync and async (with await) but neither work
googleTranslate = (key) => {
const translator = TranslatorFactory.createTranslator();
// translate returns a Promise
return translator.translate(key, i18n.locale)
.then((response) => {return response});
}
renderText() {
// getting some values....
// this loops through all the feedback information
for (var i = 0; i < components_feedback.length; i++) {
let label = (some string);
let value = (some string);
// to do: call google translate call here if Boolean(this.state.dynamicTranslate)
if (Boolean(this.state.dynamicTranslate)) {
// I am ultimately trying to save the translation string from googleTranslate()
// in label/value so I can push it into feedbacks
label = this.googleTranslate(label);
value = this.googleTranslate(value);
}
feedbacks.push({label: label, value: value, type: comp.type})
}
return (
// some stuff
feedbacks.map((feedback, index)) => {
// some stuff
<Text>{feedback.label}</Text>
<Text>{feedback.value}</Text>
// some other stuff
});
);
}
render() {
return (
<View>{this.renderText()}</View>
);
}
One of the issues I'm running into is that label/value is a Promise if translation is on. If I try to make renderText() an async method, it is also turned into a Promise which render() can't handle. No idea where to go from here.
Solved this issue. Solution is to put the loop in an async function that (ideally) gets called on construction. This loop was edited to await the returns and push to local arrays of labels and values then saves those in state. You can compare the length of those arrays to the expected length (compare length of last array being used to be positive that it has finished) and that is how you can know if the Promises have returned. Paraphrased code:
constructor(props) {
this.state = {
translatedLabels = []
translatedValues = []
}
this.asyncFunction()
}
asyncFunction = () => {
labels = []
for loop
label = await promise
labels.push(label)
//same for values
end for
this.setState({translatedLabels: labels})
}
//later
renderText() {
if (this.state.translatedLabels.length === whatever) {
// do your stuff as you know the async function has finished
}
}
render() {
return (
{this.renderText()}
);
}

Using async await on promise in svelte (#await) is not returning the desired data that is formatted in a later function call

I am currently working with a API that does not return JSON. To get around this, I take the response and push it to a array ( while formatting it to remove any indentation and split each number in the response ). I then use this array of 183 numbers and run a for loop against an array with 183 characters to generate an object ( with custom key value pairs ) from the response.
Where things get confusing is when I start to use the data in my HTML. Usually you can just say <p>{data.overallRank}</p> but I am getting the error that the object is undefined. This makes sense because the data = {} was not created until the function ran.
After searching for a solution, I cam across svelte await blocks. You can read on them here and look at the tutorial : https://svelte.dev/tutorial/await-blocks
After trying to implement this feature, I have the following code.
let playerStats = []
let proxy = "https://cors-anywhere.herokuapp.com/"
let url = proxy + "https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=Hess"
const data = {};
let promise = getPlayer();
async function getPlayer() {
return await fetch(url).then((response) => response.text())
.then((data) => {
return data;
});
}
getPlayer().then((playerData) => {
// format data
playerStats.push(playerData.replace(/\n/ig, ",").split(','));
console.log(playerStats);
// Begin object generation
// names array shortened
let names = ["overallRank", "overallLvl", "overallXP", "attRank", ]
const data = {};
for (var i = 0; i < playerStats[0].length; i++) {
data[names[i]] = playerStats[0][i];
}
console.log(data);
});
<main>
{#await promise}
<p>Search for a Player...</p>
{:then data}
<p>The data is {data}</p>
{/await}
</main>
I suggest throwing this code in a svelte editor which you can find here: https://svelte.dev/tutorial/await-blocks
The issue with this code is that it is printing out the data from the return data, which returns the unformatted data and not the object.
I want to return the object that is created after the second function getplayer().then()... so I can use that object throughout my HTML.
I hope I explained things well and thank you in advance for any help.
It is returning the formatted data because that what is returned by the promise function. In order to get the formatted data, you have to add the formatting to the chain of promise
async function getPlayer() {
return await fetch(url)
.then((response) => response.text())
.then((playerData) => {
// here your transformation
// do not forget to actually return something
return data;
});
You were actually very close to sorting it out, just a bit of confusion regarding how promises work I believe.
All you need to do is format your data within the block where the data is handled following the fetch & decode operations:
async function getPlayer() {
return await fetch(url)
.then((response) => response.text())
.then((data) => {
return formatData(data);
});
}
Your formatData() function is essentially there already, you just need minor changes in your code:
function formatData(playerData) {
playerStats.push(playerData.replace(/\n/ig, ",").split(','));
console.log(playerStats);
// Begin object generation
// names array shortened
let names = ["overallRank", "overallLvl", "overallXP", "attRank", ]
const data = {};
for (var i = 0; i < playerStats[0].length; i++) {
data[names[i]] = playerStats[0][i];
}
console.log(data);
return data;
}
Finally, you do not need to explicitly declare a promise to use it in an {#await} block, you know getPlayer() returns a promise, so you can directly use that instead:
<main>
{#await getPlayer()}
<p>Search for a Player...</p>
{:then data}
<p>Overall Rank: {data.overallRank}</p>
{/await}
</main>
See functioning REPL

How can I update a nested array with ionic4 storage

Using
openSavedForm() {
this.storage.get('test').then((val) => {
this.auditResults = JSON.parse(val);
this.audit = this.auditResults
this.auditOne = this.auditResults.siteVehicle;
console.log('pull all', this.audit);
});
}
I can view my key value pair stored items in sqlite. Here is a photo of the of the console.log
Is it possible to only update only the siteVehicle Array with
async saveFormUpdates() {
this.newAudit =this.auditOne;
await this.storage.set( 'test', JSON.stringify(this.newAudit));
console.log ("storage", this.newAudit);
}
with out deleting all the other arrays?
My async saveFormUpdates() was wrong. Turns out just saving this.audit instead of this.auditOne did everything with no further input from me.
async saveFormUpdates() {
this.newAudit = this.audit;
await this.storage.set( 'test', JSON.stringify(this.newAudit));
console.log ("storage", this.newAudit);
}

Returning value from file read with WinJS for use in page

I currently have an issue with a file read in a Windows 8/WinRT application. I have a simple navigation style app, several pages have access to the same data and I have a data.js file that defines a namespace (Data) with a number of members. One part of the application saves items to a txt file stored in the applications local data folder. But on some of the other pages I need to read this in or check for the existence of an item within the list of previously saved items. To do this I added another method into the data.js file. The trouble is, when I call this method to check for the existence of an item, it doesn't return the value straight away due to the async nature, but the rest of code in the page specific js file still seems to execute before it jumps back into the parsing. This means that the logic to check for an item doesn't seem to work. I have a feeling it's down to my use of either .done or .then but my code is as follows:
DATA.JS
var doesItemExist= function(item_id){
var appFolder = Windows.Storage.ApplicationData.current.localFolder;
//note I've tried this with and without the first "return" statement
return appFolder.getFileAsync(dataFile).then(function (file) {
Windows.Storage.FileIO.readTextAsync(file).done(function (text) {
try {
var json = JSON.parse(text);
if (json) {
for (var i = 0; i < json.items.length; i++) {
var temp_item = json.items[i];
if (temp_item.id === item_id) {
return true;
break;
}
}
} else {
return false;
}
} catch (e) {
return false;
console.log(e);
}
}, function (e) { return false;console.log(e); });
}, function (e) { // error handling
return false;
console.log(e);
});
}
WinJS.Namespace.define("Data", {
doesItemExist: doesItemExist
}); //all of the above is wrapped in a self executing function
Then on Page.js I have the following:
var add = document.getElementById('add');
if (Data.doesItemExist(selected_item.id)) {
add.style.display = 'block';
} else {
add.style.display = 'none';
}
All the variables here are assigned and debugging doesn't produce any errors, control just appears to go back to the if/else statement after it hits the getFileAsync but before it even goes through the for loop. But subsequently it does go in to the for loop but after the if statement has finished. I'm guessing this is down to the async nature of it all, but I'm not sure how to get around it. Any ideas?
thanks
A Promise should work here.
I created a new Navigation app, and added a Data.js file containing the following code:
(function () {
var appData = Windows.Storage.ApplicationData;
function doesItemExist(item_id) {
return new WinJS.Promise(
function (completed, error, progress) {
var exists = false;
appData.current.localFolder.createFileAsync("data.txt", Windows.Storage.CreationCollisionOption.openIfExists).then(
function (file) {
Windows.Storage.FileIO.readTextAsync(file).then(
function (fileContents) {
if (fileContents) {
if (fileContents = "foo!") {
completed(true);
}
else {
completed(false);
}
}
else {
completed(false);
}
}
);
},
function (e) {
error(e);
}
);
}
);
}
WinJS.Namespace.define("Data", {
doesItemExist: doesItemExist
});
})();
Note that I've simplified the code for retrieving and parsing the file, since that's not really relevant to the problem. The important part is that once you've determined whether the item exists, you call completed(exists) which triggers the .then or .done of the Promise you're returning. Note that you'd call error(e) if an exception occurs, as I'm doing if there's an exception from the call to createFileAsync (I use this call rather than getFileAsync when I want to be able to either create a file if it does not exist, or return the existing file if it does, using the openIfExists option).
Then, in Home.js, I added the following code to the ready handler:
var itemExists;
var itemExistsPromise = Data.doesItemExist(42);
itemExistsPromise = itemExistsPromise.then(function (exists) {
itemExists = exists;
var content = document.getElementById("content");
content.innerText = "ItemExists is " + itemExists;
});
itemExistsPromise.done(function () {
var a = 42;
});
var b = 0;
The code above sets the variable itemExistsPromise to the returned promise from the function in Data.js, and then uses an anonymous function in the .then function of the Promise to set the variable itemExists to the Boolean value returned from the doesItemExist Promise, and grabs the <p> tag from Home.html (I added an id so I could get to it from code) and sets its text to indicate whether the item exists or not). Because I'm calling .then rather than .done, the call returns another promise, which is passed into the itemExistsPromise variable.
Next, I call itemExistsPromise.done to do any work that has to wait until after the work performed in the .then above it.
If you set a breakpoint on the lines "var a = 42" and "var b = 0" (only included for the purpose of setting breakpoints) as well as on the line "itemExists = exists", you should find that this gives you the control you need over when the various parts are executed.
Hope that helps!