I have a function, eventQuery which fetches data from a Firebase DB. I am able to see the data is successfully pulled and returns what I understand to be an array of arrays each composed of a string and an object. First, my code:
const [activeDate, setActiveDate] = useState(new Date())
const [existingEvents, setExistingEvents] = useState({})
useEffect(() => {
eventQuery(activeDate)
.then(data => {
setExistingEvents(data);
console.log(data)
})
.then(setExistingEvents(''))
.catch(err => console.log('no events'))
}, [activeDate])
useEffect(() => {
console.log('existingEvents equals: ' + existingEvents)
}, [existingEvents])
The output of console.log(data) within the promise yields something in the form of:
[["String1.1", {"String1.2": "String1.3", "String1.4": "String1.5", "String1.6": "String1.7"], ["String2.1", {etc.}], ["String3.1", {etc.}]]
However, when I use setExistingEvents(data) to pass that array of arrays to existingEvents, and then I subsequently console log the new value, the result is:
existingEvents equals: String1.1,[object Object],String2.1,[object Object],String3.1,[object Object]
As far as I can tell, setState() is essentially running toString() on my array of arrays. Am I doing something wrong or is this an inherent part of the function? Thanks so much for your help.
Your console.log statement is actually the reason why the output looks like existingEvents was stringified (setState doesn't stringify the argument).
Instead of:
useEffect(() => {
// `existingEvents` is coerced to a string
console.log('existingEvents equals: ' + existingEvents)
}, [existingEvents])
It should be:
useEffect(() => {
console.log('existingEvents equals:', existingEvents)
}, [existingEvents])
Also, your second .then() function should be:
.then(() => setExistingEvents('')) // not .then(setExistingEvents('')) <- this causes setExistingEvents('') to be called immediately
Your problem is you're using a string append on this
console.log('existingEvents equals: ' + existingEvents)
If you want to have entire data in a string format, you can use JSON.stringify
console.log('existingEvents equals: ' + JSON.stringify(existingEvents))
Or use a separator , in console.log
console.log('existingEvents equals: ', existingEvents)
Related
setScorecardActiveVerificationsList(state, payload) {
console.log(
'beginState :>> ',
state.activeScorecardVerificationsList
)
const findIndex = state.activeScorecardVerificationsList.findIndex(
(el) => el.part_id === payload.part_id
)
console.log('findIndex', findIndex)
if (findIndex !== -1) {
const newArray = state.activeScorecardVerificationsList.filter(
(el) => el.part_id !== payload.part_id
)
newArray.push(payload)
state.activeScorecardVerificationsList = newArray
console.log(
'FoundstateactiveScorecardVerificationsList',
state.activeScorecardVerificationsList
)
} else {
state.activeScorecardVerificationsList = [
...state.activeScorecardVerificationsList,
payload,
]
console.log(
'NotFoundactiveScorecardVerificationsList',
state.activeScorecardVerificationsList
)
}
},
I'm still a bit new to Vuex but I'm having trouble with this mutation. This mutation format I've used on two other parts of the code that are working fine so this one is stumping me.
Btw, state.activeScorecardVerificationsList is an array of Objects.
I'm checking to see if the payload with part_id is already existing in the state.
IF it exists, I want to overwrite it and return the state with the newly updated object in the array.
IF this payload with the part_id does not exist, I just want to add it to the array.
Currently I'm having trouble with this part of the code:
console.log(
'beginState :>> ',
state.activeScorecardVerificationsList
)
const findIndex = state.activeScorecardVerificationsList.findIndex(
(el) => el.part_id === payload.part_id
)
For some reason, the beginState console log is showing the state with the payload.part_id (new one) almost immediately before any of the other lines of function is run. therefore, findIndex is returning 0 and it is always overwriting the state, not adding to it.
I'm not entirely sure how the state is already being sent with the new payload. I have a feeling my syntax or understanding of setting a vuex mutation might be off
Any ideas?
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
I already initialize the data.
data () {
return {
current_product: {},
current_ID: '',
}
}
Then, I fetch data from a REST API on lifecycle created hook.
created () {
var skuID = this.$store.state.selected_productSKU.productSKU_ID
axios.get(`http://localhost:8081/api/products/${skuID}`)
.then(response => {
this.current_ID = response.data.product_ID
this.current_product = response.data
})
.catch(e => {
alert(e)
})
}
And finally, I use computed property to get some value
// THIS JUST RETURN ['XL', 'M']
focusedProduct_SKUS_NoDupSizes () {
var newArr = this.current_product.product_SKU.filter((sku, index, self) =>
index === self.findIndex(t => (
t.productSKU_size === sku.productSKU_size
))
)
var x = newArr.map(a => a.productSKU_size)
return x
}
The vue instance show expected result
But if i call {{ focusedProduct_SKUS_NoDupSizes }} in template.
It doesn't rendered.
The browser return error Error in render: "TypeError: Cannot read property 'filter' of undefined"
What is happening? My first guess is the computed property using the initial structure of current_product which is {} empty object. But isn't that how to initialize an object?
Because of:
computed:
// ...
focusedProduct_SKUS_NoDupSizes () {
var newArr = this.current_product.product_SKU.filter((sku, index, self) =>
^^^^^^^^^^^
You should initialize product_SKU with an empty array:
data () {
return {
current_product: {product_SKU: []}, // changed here
current_ID: '',
}
}
This is needed because the computed property will be executed right away, even before your Ajax gets a chance to return.
Declare it as empty so the computed doesn't throw an error. When the Ajax fulfills, it will recompute automatically.
Even though the Ajax is started at the created(), it won't return before the computed is executed for the first time. More details about this here.
I think I may running into a callback hell type scenario or this may be an issue with scope. I want setState with allLeagues array once the .map function is finished running. Problem is, when the .map function is done and this.setState({leagueAL: allLeagues)} is ran, the state is set to an empty array. I do not want to run this.setState inside the .map and set it multiple times. Any thoughts on how I can make the data persist into the state?
getLeagueMatches = () => {
let allLeagues = []
if(this.state.leagueMatchesInfo != null){
this.state.leagueMatchesInfo.map((league, id) => {
let leagueID = league.league_id;
fetch(`https://apifootball.com/api/?action=get_events&from=2017-09-11&to=2017-09-11&league_id=${leagueID}&APIkey=<APIKey>`)
.then(res => res.json())
.then(event => {
//console.log(event)
if(event.error){
//console.log(event.error)
}else{
league.matches = true;
//console.log(league)
allLeagues = [...allLeagues, league]
}
})
console.log(allLeagues)
})
this.setState({
leagueAL: allLeagues
})
}//end if(65)
};//end renderItem
.map() returns a new array. You'll need to catch it in a variable. In map, you should have a function that does something on each element.
allLeagues = this.state.leagueMatchesInfo.map((league, id) => {
...
}
this.setState({
leagueAL: allLeagues
})
Then setState after the map.
The issue is that you're not updating the allLeagues array until the promises have resolved. However, setState is being called before any of this even happens.
I would look into something like Promise.all(). Then you can create an array of promises with each call to fetch. Then you can call .then off your Promise.all() and set the state within the .then.
Just now I started using AsyncStorage. I tried storing input text value like this:
class Sample extends React.Component{
constructor(props){
super(props);
this.state = {
Name:' ',
};
}
componentDidMount() {
AsyncStorage.getItem("Name").then((value) =>{
this.setState({"Name":value})
}).done();
handleChange(e){
AsyncStorage.setItem("Name", e.nativeEvent.text)
this.setState({
email: e.nativeEvent.text
})
}
render(){
return(
<View>
<TextInput
style={styles.textContainer}
value={this.state.Name}
placeholder="Name"
onChange={this.handleChange.bind(this)}/>
</View>
)
}
For this it is working correctly, but i want to add a record into an array instead of changing the record every time. I want to push the record into an array and need to display the total array data in the view, (i.e) I need previously avilable data also.
Stringify Array
Use JSON.stringify and JSON.parse to store an array as a value via AsyncStorage.
Store / Stringify
const stringifiedArray = JSON.stringify(somearray)
Restore / Parse
const restoredArray = JSON.parse(stringifiedArray)
Usage with AsyncStorage
return AsyncStorage.getItem('somekey')
.then(req => JSON.parse(req))
.then(json => console.log(json))
.catch(error => console.log('error!'));
const someArray = [1,2,3,4];
return AsyncStorage.setItem('somekey', JSON.stringify(someArray))
.then(json => console.log('success!'))
.catch(error => console.log('error!'));
for setting
AsyncStorage.setItem('name', JSON.stringify(your array));
for getting
AsyncStorage.getItem('name', (error, result) => {
this.setState({ name: JSON.parse(result) }, function () { });});
None of the other answers give an applied demonstration of pushing values back to the array (as opposed to completely replacing it). Below is an example:
// You will first want to set an initial array:
AsyncStorage.setItem("myNumbers", [1, 2, 3])
// Now if we want to append other values to it.
// It's important to enclose it in bracket (otherwise you'd get an error trying to modify an object)
const arr = [await AsyncStorage.getItem("myNumbers")]
arr.push(15)
AsyncStorage.setItem('myNumbers', arr)
If you'd like to get the final result:
const modified = await AsyncStorage.getItem("myNumbers")
console.log(modified) //gives us 1, 2, 3, 15