React Native State not updating with an empty Array - javascript

Hi stackoverflow people I know this has been asked about a million times. However I don't think I have found an answer to my problem!
Long story short I am updating a state in my react native app only if a statement is true. What I am experiencing is this state not being updated somehow.
const emptyArray = []
const [collapsed, setCollapsed] = useState(true);
const [selectedGem, setSelectedGem] = useState(false);
const [usedGem, setUsedGem] = useState(emptyArray);
const [selectedPropType, setSelectedPropType] = useState('all');
const randomItem = (items) => {
return items[Math.floor(Math.random()*items.length)];
}
const getRandomQuestion = () => {
let selectableGems = gems
const maxGems = selectableGems.length;
let tempGems = [];
if(usedGem.length >= maxGems) {
setUsedGem(emptyArray)
}
for (let i=0; i<maxGems; i++)
{
if(usedGem.length === 0 || usedGem.find(gem => gem === i) === undefined) {
tempGems.push(i)
}
}
const randomGemNumber = randomItem(tempGems)
setUsedGem([...usedGem, randomGemNumber])
setSelectedGem(selectableGems[randomGemNumber])
}
Basically if(usedGem.length >= maxGems) {happens only when all the gems have been randomised once (there are 130 item in the gems variable). I'd expect then the usedGem to be empty in the for but this isn't the case.
I have tried a few solutions I found without luck. I know this has to do with async but I can't figure it out! Anyone could help me please?

Here this might help. The thing is you can't get instant update after setting state
const getRandomQuestion = () => {
let selectableGems = gems
const maxGems = selectableGems.length;
let tempGems = [];
let gems = Array.from(usedGem);
if(gems.length >= maxGems) {
gems = []
}
for (let i=0; i<maxGems; i++)
{
if(gems.length === 0 || gems.find(gem => gem === i) === undefined) {
tempGems.push(i)
}
}
const randomGemNumber = randomItem(tempGems)
setUsedGem([...gems, randomGemNumber])
setSelectedGem(selectableGems[randomGemNumber])
}

Related

Element is not inserting into array in a loop and also looping twice JS/React

I try to insert a string into a particular index of object if condition is true inside a forloop but its not inserting of some reason. I tried to use push and append and splice but splice just inserting entire string as an new object into the array and i need it to just append to existing object. Any ideas how to make it work?
Data looks like that:
const [concerts, setConcerts] = useState([]);
const [tickets, setTickets] = useState([]);
const [limit, setLimit] = useState(25);
const navigate = useNavigate();
const [button, setButton] = useState(false);
const [array, setArray] = useState([]);
//Raw JSON Date example: "2023-02-08T23:15:30.000Z"
let currentDate = new Date().toJSON().slice(0, 10);
const json = { available: "true" };
useEffect(() => {
const loadConcerts = async () => {
const resConcerts = await axios.get("/data/concerts");
const resTickets = await axios.get("/data/tickets");
let table = [];
setTickets(resTickets.data);
// getting all concerts above today
const filteredData = resConcerts.data.filter((concert) => {
return concert.datum >= currentDate;
});
filteredData.forEach((element) => {
table.push(element);
// table.splice(10, 0, { status: "available" });
});
setArray(table);
for (let i = 0; i < resTickets.data.length; i++) {
for (let j = 0; j < filteredData.length; j++) {
if (
resTickets.data[i].concertid == filteredData[j].id &&
resTickets.data[i].booked == 0
) {
table.push({ status: "avaiable" });
// table.splice(10, 0, { status: "available" });
}
}
}
setArray(table);
// filteredData.forEach((concert) => {
// for (const ticket of tickets) {
// if (concert.id == ticket.concertid && ticket.booked == 0) {
// table.push(json);
// }
// }
// });
setConcerts(
filteredData.sort((a, b) =>
a.datum > b.datum ? 1 : a.datum < b.datum ? -1 : 0
)
);
};
console.log("from use effect: " + array.length);
loadConcerts();
}, []);
After using splice method:
Update
Problem is solved. I used Object.assign() helped to append string to existing object in array. Actually i had to insert another object, not a single variable.
The problem is you are trying to push a string "available" into an array-of-objects.
Here you see the object with a property datum:
const filteredData = resConcerts.data.filter((concert) => {
return concert.datum >= currentDate;
});
Yet below when you push, you are not pushing an object into the array which is problematic. It should probably be something like this but you have to verify:
Instead of this:
filteredData.push("available");
Domething like this:
filteredData.push({ datum: '', status: 'available' );
I don't know what your data object is but it's an object not a string you need to add to that array.
The looping twice is likely from React 18 New Strict Mode Behaviors. It intentionally unmounts/remounts components to fire your useEffect calls twice - so that you can identify problematic side effects. If you remove <StrictMode> or run in production that double-looping should not occur.
Problem solved. Push() neither splice() method didn't helped. What helped me to append my object to another object without changing the data was Object.assign() function
for (let i = 0; i < resTickets.data.length; i++) {
for (let j = 0; j < filteredData.length; j++) {
if (
resTickets.data[i].concertid == filteredData[j].id &&
resTickets.data[i].booked == 0
) {
Object.assign(filteredData[j], obj);
}
}
}

Uncaught TypeError: Cannot read properties of undefined (reading '0'), Summing useState arrays

const [lnames, setlNames] = React.useState();
const [lnums, setlNums] = React.useState();
React.useEffect(() => {
axios.get("http://localhost:7001/lunch").then(response => {
let arr1 = [];
let arr2 = [];
response.data.forEach(c => {
arr1.push(c.table_id);
arr2.push(c.table_num_count);
});
setlNames(arr1);
setlNums(arr2);
});
}, []);
const [dnums, setdNums] = React.useState();
React.useEffect(() => {
axios.get("http://localhost:7001/dinner").then(response => {
let arr1 = [];
response.data.forEach(c => {
arr1.push(c.table_num_count);
});
setdNums(arr1);
});
}, []);
const [bnums, setbNums] = React.useState();
React.useEffect(() => {
axios.get("http://localhost:7001/breakfast").then(response => {
let arr1 = [];
response.data.forEach(c => {
arr1.push(c.table_num_count);
});
setbNums(arr1);
});
}, []);
const customer_count_breakfast = bnums;
const customer_count_lunch = lnums;
const customer_count_dinner = dnums;
let sumArray = []
if (lnums & lnums.length > 0) {
//sumArray = lnums.map((l, i) => l + bnums[i] + dnums[i]);
for (let i = 0; i < lnums.length; i++) {
sumArray[i] = bnums[i] + lnums[i] + dnums[i];
}
}
// IF COMMENT ABOVE AND UNCOMMENT HERE THE ERROR IS GONE BUT sumArray is not computed
// if (lnums && lnums[0]) {
// //sumArray = lnums.map((l, i) => l + bnums[i] + dnums[i]);
// for (let i = 0; i < lnums.length; i++) {
// sumArray[i] = bnums[i] + lnums[i] + dnums[i];
// }
// }
Hello I have the above code giving me the following error at the if loop condition : Uncaught TypeError: Cannot read properties of undefined (reading '0'). I think I know why the error is being displayed. It is indicating that I am trying to access a property or index of a variable that is undefined, this is most likely due to the useEffect, where when I call for the if condition the value is not set yet, so it is undefined and thus does not have a length. When I try to comment the first if condition and uncomment the second, I get no more errors but the summation does not work, it returns an empty array.
How would I be able to sum the values of .useState() variables in this case?
You need to look into react lifecycle and useMemo.
read about lifecycle: https://www.w3schools.com/react/react_lifecycle.asp
read about useMemo: https://www.w3schools.com/react/react_usememo.asp
Here is a quick example where useEffect puts numbers into an array, useMemo has dependency on those arrays and adds all the numbers together.
import { useEffect, useState, useMemo } from "react";
export default function App() {
const [arr1, setArr1] = useState([]);
const [arr2, setArr2] = useState([]);
// called everytime arr1 or arr2 changes. Which causes react to rerender.
// first run sum = 0
const sum = useMemo(() => {
let res = 0;
if (arr1.length && arr2.length) {
for (let i = 0; i < arr1.length; i++) {
res += arr1[i] + arr2[i];
}
}
return res;
}, [arr1, arr2]);
// called once, updated setArr1 causing sum to be called
useEffect(() => {
setArr1([1,2,3]);
}, []);
// called once, updated setArr2 causing sum to be called
useEffect(() => {
setArr2([4,5,6]);
}, []);
return (
<div>
<p> sum: {sum} </p>
</div>
);
}
Essentially In your code you are calling the arrays before useEffect has finished setting their values.
I solved the issue by adding a try-catch statement, not sure if it is feasible at all
try {
for (let i = 0; i < lnums.length; i++) {
sumArray[i] = bnums[i] + lnums[i] + dnums[i];
}
console.log("Statement was successful");
} catch (error) {
}

(CLOSED) Return statement never gets called. NodeJS loop is still finite and doesn't go forever. What's happening?

I was able to fix this by changing the contents of the .push() of allTeams (second to last instance of .push() in the code)
The final return statement should return an array of objects. (allObjectTeams, right after await browser.close()), BUT it returns undefined
Placing the variable right above the return statement still does not solve the issue.
Commenting the biggest loop (the one that iterates over blocks.length) makes that final return statement work but I don't know what part of said loop is messing it up, Commenting out anything that does an action to this said variable doesn't solve the issue
makeTeam() is an instance of recursion but it looks fine to me. Essentially taking a random set of elements from the people array and placing it as a property of an object, then to add than object to an array,
The function also removes the specific elements that were chosen from that array so if there are still more, It calls itself again. A heads-up but I don’t think it does anything.
I am using Puppeteer.
Code (JS):
const start = async () => {
let teamSize = 2
let allObjectTeams = [] //This is the variable I am trying to return
let allTeams = []
const browser = await require("puppeteer").launch()
const page = await browser.newPage()
await page.goto("https://www.when2meet.com/?16521246-5ySm2")
const blocks = await page.$$("#GroupGridSlots > div")
for (let i = 0; i < blocks.length; i++) { // This is the loop I'm talking about, blocks.length is finite. This loop does not go on forever for the return statement never to be called.
await blocks[i].hover()
const team = await page.$eval("#Available", ((availableList, teamSize) => {
const people = availableList.innerHTML.split("<br>")
people.pop()
function getMultipleRandom(arr, num) { // Grabs random elements from array
const shuffled = [...arr].sort(() => 0.5 - Math.random());
return shuffled.slice(0, num);
}
if (people.length == teamSize) {
const availableTeam = {}
availableTeam.people = people
return availableTeam
} else if (people.length > teamSize) {
const teamArray = []
const makeTeam = (currentLength) => {
const availableTeam = {}
const teamPeople = getMultipleRandom(people, teamSize)
availableTeam.people = teamPeople
teamArray.push(availableTeam)
if ((currentLength - teamSize) > teamSize) {
teamArray[teamArray.length - 1].people.forEach(person => {
people.forEach(availablePerson => {
if (availablePerson == person) {
people.splice(people.indexOf(person), 1)
}
})
})
makeTeam(currentLength - teamSize)
}
}
makeTeam(people.length)
return teamArray // returns array of Objects, But THIS is not the one
} else {
return
}
}), teamSize)
if (!team) {
} else if (!Array.isArray(team) && allTeams.includes(team.people.toString())) {
return
} else if (Array.isArray(team)) {
team.forEach(t => {
allTeams.forEach(registeredTeam => {
if (t == registeredTeam) {
team.splice(team.indexOf(t), 1)
}
})
})
for (let i = 0; i < team.length; i++) {
allTeams.push(team[i].toString())
const availableDate = await page.$eval("#AvailableDate", (availableDate => {
return availableDate.textContent.split("Sunday ").pop()
}))
team[i].time = availableDate
allObjectTeams.push(team[i])
}
} else if (team.hasOwnProperty("people")) {
allTeams.push(team.people.toString()) // this was changed to allTeams.push(team.toString())
const availableDate = await page.$eval("#AvailableDate", (availableDate => {
return availableDate.textContent.split("Sunday ").pop()
}))
team.time = availableDate
allObjectTeams.push(team)
}
}
await browser.close()
return allObjectTeams // This return statement returns undefined. THE OTHERS DO NOT
}
start().then((arr) => {
console.log(arr)
})

JS recursive mergeSort with objects

Hihi,
My question is simple. I'm trying to implement mergesort but having a limitation with the structure of my project
I have a file called sort.js
const selSort = require('./selectionSort');
const bubSort = require('./bubbleSort');
const inSort = require('./insertionSort');
const merSort = require('./mergeSort');
const sort = (arr) => {
const array = arr;
return {
...selSort(array),
...bubSort(array),
...inSort(array),
...merSort(array),
};
};
As you can see I'm trying to implement multiple sort algorithm and make an object
well, now while I started doing the MergeAlgorithm (a recursive sort algorithm) I faced with the problem of the objects in JavaScript
const merge = (left, right) => {
const result = [];
while (left.length && right.legnth) {
result.push(left[0] < right[0] ? left.shifth() : right.shifth());
}
return [...result, ...left, ...right];
};
const merSort = (array) => ({
mergeSort: () => {
if (array.length === 1) {
return array;
}
const middle = Math.floor(array.length);
const leftArr = array.slice(0, middle);
const rightArr = array.slice(middle);
return merge(this(leftArr).mergeSort(), this(rightArr).mergeSort());
},
});
module.exports = merSort;
I cant call mergeSort() and pass to it the left and right array without calling itself again.
Is there anyway to solve this?
I tried using this but it didn't worked
I think there is no way to achive what I want
Why are you using the spread operator ( ... ) all the time ? Also why are you reassigning the arr argument to a constant?
This should work just fine
const selSort = require('./selectionSort');
const bubSort = require('./bubbleSort');
const inSort = require('./insertionSort');
const merSort = require('./mergeSort');
const sort = (arr) => {
return {
selSort(arr),
bubSort(arr),
inSort(arr),
merSort(arr),
};
};
Also for the sorting code this should work
function mergeSort(unsortedArray) {
if (unsortedArray.length <= 1) {
return unsortedArray;
}
const middle = Math.floor(unsortedArray.length / 2);
const left = unsortedArray.slice(0, middle);
const right = unsortedArray.slice(middle);
return merge(mergeSort(left,), mergeSort(right));
}
function merge(left, right) {
let resultArray = [],
leftIndex = 0,
rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
resultArray.push(left[leftIndex]);
leftIndex++;
} else {
resultArray.push(right[rightIndex]);
rightIndex++;
}
}
return resultArray
.concat(left.slice(leftIndex))
.concat(right.slice(rightIndex));
}
module.exports = mergeSort;

Adding numbers from array in useEffect

I am trying to use hooks to add numbers from an array together. Currently it's a voting system. The result of adding all the numbers using a map statement gives me 0. I am pretty sure this has to do with useState not updating in time to add the numbers, therefore it's always giving me zero. I know I could put them in a separate array, and add that, but that seems a little verbose for something that would seem so simple.
Here is the code I have that produces 0
const PollResultsContainer = (props) => {
const option = props.option
const [totalVotes, setTotalVotes] = useState(0)
useEffect(() => {
let newVote
if (option.length > 0) {
option.map(opt => {
newVote = opt.optionVotes + totalVotes
})
}
setTotalVotes(newVote)
}, [totalVotes])
console.log(totalVotes)
return (
<>
<div className='poll-results-div'>
<TitleCardNS title={`${totalVotes}`} size='2.5rem' align='center' color='white' />
</div>
There is not need to store it in a state.
const PollResultsContainer = ({option}) => {
let totalVotes = option.reduce((acc, {optionVotes}) => acc + optionVotes, 0);
console.log(totalVotes);
};
I don't think you need any state or effect in this component :
const PollResultsContainer = (props) => {
const option = props.option
let totalVotes = 0;
if (option.length > 0) {
option.forEach(opt => {
totalVotes += opt.optionVotes
})
}
console.log(totalVotes)
I added another variable into the equation. This probably solved the problem of useState not updating in time.
const PollResultsContainer = (props) => {
const option = props.option
const [totalVotes, setTotalVotes] = useState(0)
let newVote = 0
useEffect(() => {
if (option.length > 0) {
option.map(opt => {
newVote = opt.optionVotes + newVote
console.log(newVote)
})
}
console.log(newVote)
setTotalVotes(newVote)
}, [totalVotes])
console.log(totalVotes)

Categories