Array empty even after a loop - reactjs

I'm trying to fill an array with some registers from a database. However, even after retrieving said registers and place them into the array, after the loop the array stays empty
const userParties = [];
userFollowing.forEach(element => {
// Here's when I gather the information that I need
dispatchGetUserEvents(element.user, response => {
userParties.push(response);
console.log(userParties); // Here the array is full of elements, like it's supposed to be
});
});
console.log(userParties); // However, here 'userParties' return '[]'
this.setState({ followUsersEvents: userParties });
this.setState({ userImage: userImg });
I tried to update the state array on the loop, but I had no luck there either.
'userParties' is not a state array btw.

const userParties = [];
userFollowing.forEach(element => {
// Here's when I gather the information that I need
dispatchGetUserEvents(element.user, response => {
userParties.push(response);
console.log('dispatchGetUserEvents', userParties); // Here the array is full of elements, like it's supposed to be
});
});
console.log('outside', userParties); // However, here 'userParties' return '[]'
this.setState({ followUsersEvents: userParties });
this.setState({ userImage: userImg });
run this code and you will see that outside will be printed first and dispatchGetUserEvents later, as I mentioned in comments dispatchGetUserEvents is async function, so first will be executed console.log('outside', ...);

Related

React Native: update an Array inside an Object

i currently have an object and inside this object i have multiple objects and Arrays. I want replace an Array inside this object with a new Array, so i thought of making a copy of the entire object and simple replace the Array i wan to change with the updated Array. My problem is i couldnt complete my code, i have the idea of how to do it but cant execute it.
setListings(listings=>
listings.map(item =>{
if(item.id === msg.id){
//console.log(item)
//console.log(item.Message)
const newMessages = [msg,...item.Messages]
//console.log(newMessages)
return console.log([msg,...item.Messages],{...item}) // just for testing purpose i
am returning a console log
to see what it will get me. Not correct.
}
return item;
})
);
So basically listings is my state variable, here console.log(item) prints out the entire object, console.log(item.Messages) prints out the current Messages Array which i want to replace, console.log(newMessages) prints out the new Messages Array which i want to replace the current Messages array with.
cartItem.map((food,index)=> {
if(food.food_id == newFoodItem.food_id && food.id == newFoodItem.id){
const AllFoodData = cartItem
AllFoodData[index] = newFoodItem
AsyncStorage.setItem('#Add_cart_Item', JSON.stringify(AllFoodData))
.then(() => {})
.catch(err => console.log(err))
ToastAndroid.showWithGravityAndOffset('Cart Replace Successfully',ToastAndroid.LONG,ToastAndroid.BOTTOM,25,50 )
}
})
So basically what i want to achieve here is to add the msg object to the existing Messages Array.
Since lsitings is an Array of objects using the .map i can spread through each object and check if the id of that object is each to my msg.id. if that is true then i want to return a copy the that specific listing and edit the Messages Array within [msg, ...item.Messages] otherwise return the existing item.
setListings(listings=> listings.map(item => {
if(item.id === msg.id) {
return {
...item,
Messages: [msg, ...item.Messages]
}
}
return item;
}));
});

Defining dynamic Array in Typescript?

I have a requirement where i want to read a particular value x(that is auto-generated everytime) in a loop of say n times. Now, i want to store these autogenerated values of x, so, that i can later use them and iterate over it to perform my tests(protractor).
The way, i am trying to do is by creating an Array, using let list: string[] = [];. Now, i am pushing the values to my defined list using, list.push[x]; in each iteration. By the end of loop expecting to get the resulting Array having n values of x(string) in my list array. In order to validate, i did console.log(list); in each iteration and i can see that these values are being pushed in the defined list.
Later, in my code if i am trying to access these elements using let item = list[0]; i am getting the undefined value.
I think i need to initialize the Array to some particular size having default values initially and then modify them later in the loop. But, being new to TypeScript i am not able to find a solution on how to do it. Please help, TIA!!
Here, is the snippet below :
const tests = [
{type: 'admin', id='', uname='foo', pass='bar'},
{type: 'super', id='', uname='foo1', pass='bar'},
{type: 'normal', id='customId', uname='foo', pass='bar'}
];
let list: string[] = [];
// let list = [ //this is the final list that i got from the console.log(list);
// 'QR417msytVrq',
// 'V0fxayA3FOBD',
// 'QnaiegiVoYhs'];
describe(`Open Page `, () => {
//Code to get to the page
beforeAll(async () => {
//initialize page objects
});
describe(`Login User `, async () => {
tests.forEach(test => {
it(` should login user with `+test.type, async () => {
//....
//....
// On Success
const myId = userPage.getUID().getText();
list.push(myId);
console.log(list);
console.log(list.length);
});
});
});
describe(`Delete User`, async () => {
// describe(`Confirmation `, async () => {
console.log(list);
// list.forEach(item => { //this code doesn't gets executed and wasn't giving any error, so, commented out and tried to access the first element which is undefined.
let item = list[0];
console.log(item); //getting undefined value here.
it(` should select and Delete the User having id as ` + item, async () => {
//code to remove the user having id as item.
});
// });
});
});
Options to test deleting a user:
Ultimately, it's bad practice to make tests dependent on other tests.
That said, two or possibly three options which should work:
A: Iterate through list of users within one test
describe(`Delete User`, async () => {
describe(`Confirmation `, () => {
it(`Log all users out who previously logged in`, async () => {
list.forEach((item) => {
console.log(item);
});
});
});
});
Since the list array is populated by the previous test, inserting the code dependent on it inside of the next test would ensure that it has values to work with.
B: Login and delete user in one test
describe(`Login and delete user `, async () => {
tests.forEach(test => {
it(` should login and delete user with ` + test.type, async () => {
const myId = userPage.getUID().getText();
// Select and delete myId here
});
});
});
You may be able to remove the list array entirely by putting the entirety of the user flow into one large integration test.
C: Use mock data (may not be applicable if data is random)
describe(`Delete User`, async () => {
const list = ["QR417msytVrq", "V0fxayA3FOBD", "QnaiegiVoYhs"];
describe(`Confirmation `, () => {
list.forEach((item) => {
it(
` should select and Delete the User having id as ` + item,
async () => {}
);
});
});
});
If you know what the values to delete are going to be ahead of time, you can add them in manually. If the values are randomly generated, this won't work.
Other problems:
Testing order of execution
The dynamic array syntax you're using looks right however you appear to have an order of execution problem in your tests.
The code in the describe functions that is outside of the specs (the it blocks) is executed before any of the code inside of the specs is. The testing framework will traverse the tree of describe blocks, executing any code it finds but only taking note of the it specs. When it's finished this, it then executes the it specs it found in sequential order.
When you attempt to save the value of list[0], the 'Login User' specs have yet to be executed. More specifically:
describe(`Login User `, async () => {
tests.forEach(test => {
it(` should login user with ` + test.type, async () => {
// This code is executed AFTER the code in the 'Delete User'
// block but BEFORE the 'Delete User' spec
const myId = userPage.getUID().getText();
list.push(myId);
});
});
});
describe(`Delete User`, async () => {
// This code is executed before any specs are run
let item = list[0];
// List is [] when item is initialized
// The following spec will therefore not work as item is undefined
it(` should select and Delete the User having id as ` + item, async () => {
});
});
A possible solution to this would be to change the string of the 'Delete User' spec to something like ' should select and Delete first User' as well as move all the code outside of the spec to inside.
Describe blocks should not return promises
Your code sample has describe blocks (specifically 'Login User', 'Delete User', and 'Confirmation') which return Promises. You should remove the async in front of the function declarations. The specs can and should remain the same. For example:
describe(`Login User `, () => {
Object syntax
The tests object at the start of your sample isn't using JS/TS object syntax. Each key should be followed by a colon before the value instead of an equals sign. You likely meant to write:
const tests = [{
type: 'admin',
id: '',
uname: 'foo',
pass: 'bar'
},
{
type: 'super',
id: '',
uname: 'foo1',
pass: 'bar'
},
{
type: 'normal',
id: 'customId',
uname: 'foo',
pass: 'bar'
}
];
Sources:
Jest docs describing order of execution
SO on Promise returning in describe blocks

Array is empty after for loop

I'm setting an array before a for loop, inside the for loop I use .push() to add data to the array but after this loop the array is empty.
MessageNotification.find({for: req.user.id}, (err, notifications) => {
var userdata = [];
notifications.forEach((notif) => {
User.findById(notif.from, (err, user) => {
userdata.push({
id: user._id,
username: user.username,
thumbnail: user.thumbnail
});
});
});
console.log(userdata);
});
As you can see on the code I am running a mongoose query to find all notifications for a specific id, then, I am setting an array to get details about the sender of each notification. Inside a forEach loop I save the results in the array. Console.log on line 12 returns an empty array [] even though User.findById on line 4 gets the User data
The problem is you are doing and asynchronous call in forEach. You should either use async/await with for..of or promises in such cases.
In your case, actually there is no need to do multiple calls on User model, you can get the desired result in a single query. Try the below code:
MessageNotification.find({
for: req.user.id
}, (err, notifications) => {
const fromArr = notifications.map(({
from
}) => from); // taking out **from** values from all notifications
User.find({
_id: {
$in: fromArr
}
}, (err, users) => { // single query to get the data
const userData = users.map(({
_id: id,
username,
thumbnail
}) => {
return {
id,
username,
thumbnail
};
});
console.log(userData);
});
});
The problem here is actually that you're calling .forEach with an async calls inside. Rather than iterating over each item in the array, and running a separate query for each, you should use the $in operator which will check if any values match items within the array, with a single query.

In React setState(), how to refill an array?

I'm doing a poker game practice, I want to re-shuffle the pokers each time when it is almost used up, but I cannot refill the pokers array with another array in setState(), the pokers array is empty at the end and throw the error.
deal=()=>{
// At the beginning, there are 104 pokers, there is a button to trigger this function;
let tmpPoker = this.state.localPokers.pop();
if(this.state.localPokers.length <= 5){
let temp = shuffle([...allPokers]);
console.log('Temp_outside');
console.log(temp);
console.log("Temp_outside")
this.setState({
localPokers: temp,
},()=>{
tmpPoker = this.state.localPokers.pop();
console.log("Temp_inside");
console.log(temp);
console.log("Temp_inside");
this.setState({
localPokers: this.state.localPokers,
},()=>{
console.log("localPokers");
console.log(this.state.localPokers);
console.log("localPokers");
});
return tmpPoker
});
}
this.setState({
localPokers: this.state.localPokers
});
return tmpPoker
}
This is console output
You dont use the state inside setState like this, here is the correct way:
this.setState((state)=>({
localPokers: state.localPokers
}));

How do i save my to-do app's list in local storage?

This is what I have so far: https://gist.github.com/justgoof9/f6250cdbd615bda139ef8d56375fa12c
So when I add items to the list then when I refresh the browser, I want it to still save. I want to do it with JSON but don't know how. Can anyone help me?
Yes you can achieve it by using local storage, so whenever you push something to your to Todo list, save the updated list in local storage and then when you are rendering in the UI use the data that is stored in local storage. Here is a small example to achieve this --> https://www.w3schools.com/html/html5_webstorage.asp
Hope this solved your problem.
Hi storing objects in LocalStorage is a bit tricky because LocalStorage accepts strings, but JSON.stringify() comes to the rescue! In you function addToList:
addToList = input => {
let listArray = this.state.lists;
listArray.push(input);
this.setState({
list: listArray,
userInput: ""
});
};
You want to add a LocalStorage call that saves the list from this.state into LocalStorage, like this:
addToList = input => {
let listArray = this.state.lists;
listArray.push(input);
this.setState({
lists: listArray,
userInput: ""
}, () => {
window.localStorage.setItem('savedList', JSON.stringify(this.state.lists));
});
};
And to retrieve it, you need to parse it back into an array/object, like this:
componentDidMount() {
const list = window.localStorage.getItem('savedList');
const parsedList = JSON.parse(list);
this.setState({
lists: parsedList,
})
}
Now every new item you add is saved to localStorage and is retrieved on refresh, all that is left is to apply the same logic to removing items, like this:
listOnClick = index => {
var arr = this.state.lists;
arr.splice(index, 1);
this.setState({ lists: arr }, () => {
window.localStorage.setItem('savedList', JSON.stringify(this.state.lists));
});
};
You also had a typo in addToList, you were assigning to this.state.list instead of this.state.lists

Resources