Setting Array in ReactJS w/ Hooks - javascript

I currently have an array of FooBar objects
interface FooBar {
foo: string,
bar: string,
correct: string,
other: string[]
}
const [arrOfObj, setArrOfObj] = useState<FooBar[]>([
{ "foo": "foolicious ", "bar": "barlicious", "correct": "foobarlicious", "other": ["oof", "f00", "rab", "r#b"]},
]);
const [shuffledArrOfObj, setShuffledArrOfObj] = useState<FooBar[]>([
{ "foo": "", "bar": "", "correct": "", "other": [""]},
]);
However I want to randomly shuffle the "other" array in each object so I have a shuffle function:
useEffect(() => {
(async () => {
const act = await shuffleObjs();
setShuffledArrOfObj([...act]);
})();
}, [arrOfObj]);
const shuffleObjs = () => {
let holdArr = [...arrOfObj];
for (let i: number = 0; i < holdArr.length; i++) {
holdArr[i].other = await handleShuffle(holdArr[i].other);
}
}
const handleShuffle = async (array: string[]) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
However, if I console.log(holdArr) at the end of the "shuffleObjs" function, the array of objects is totally different than the array of objects stored in the shuffledArryObj state.
Am I setting the array state the wrong way, or is there something I am missing?
EDIT: Typo wasn't the problem, it's still not working correctly. I also tried adding arrOfObj to the dep array.

You're missing two things:
useEffect(() => {
(async () => {
const act = await shuffleObjs();
setShuffledArrOfObj([...act]);
})();
}, [arrOfObj]); //<-- Add arrOfObj to dependency Array
const shuffleObjs = () => {
let holdArr = [...arrOfObj];
for (let i: number = 0; i < holdArr.length; i++) {
holdArr[i].other = await handleShuffle(hold[i].other); //<-- change hold[i] to holdArr[i]
}
}

Related

Zustand setState outside of component doesn't update

My store is set inside store.js as all the other Zustand stores:
const retryStore = create(set => ({
retry_n: 0,
setGRetry: (retry_n) => set(state => ({
...state,
retry_n,
})),
}));
export { retryStore };
inside my #/utils/get.js file I try to update the number by 1, using setState as:
const retry_n = retryStore.getState().retry_n
const xxx = xxxStore.getState().xxx
const xxxx = xxxxStore.getState().xxxx
var j=0;
const maxretry = 20;
const myFetch = async () => {
try {
let url = `...`
while(j < maxretry){
console.log('while try n:',j) // 1,2,3... ecc
console.log('get.js retry_n:',retry_n) // always 0
if (isItRetry){ // TRUE
retryStore.setState({ retry_n: retry_n + 1})
console.log('playThis retry_n now:',retry_n) // always 0
}else{
...
}
if (a != b){ ... return }
j++
}
etc...
shouldn't this increment by 1 each loop? why is always 0? I use other stores the same way in the same file and all work but this one.

How to Receive cypress interception fixture twice but in different format?

I'm a beginner with Cypress and I am stuggeling with the following:
I am calling the following from my test file:
cy.SetupClassificationsStubFixture(1);
This refers to the following command:
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
}).as('classifications')
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications/*', slicedClassifications)
}).as('classifications') });
As you can see this customcommand is intercepting 2 api request. Namely:
** /api/classifications
** /api/classifications/ *
The first interception is with []
The second intercecption needs exactly the same response buth without brackets []
But you already understand that both respons are now with brackets '[]'. I tried to make a second fixture file without [], but the the slice function is not working.
So I need:
The second intercept like:
{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}
But I get:
[{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}]
How could I get this array back without []? Thankyou indeed!
UPDATE:
I am trying now the following:
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
}).as('classifications')
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
const arr2 = slicedClassifications
const obj5 = Object.fromEntries(arr2)
cy.intercept('GET', '**/api/classifications/*', obj5)
}).as('classification')});
But this give me a emtpy .json file. It the respons is not just ' {} '
There looks to be some brackets out of place in the code.
I would also recommend using different alias names, otherwise the calls to cy.wait('#classifications') may not work as you expect.
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
.as('classifications')
const firstClassification = slicedClassifications[0] // just first item
cy.intercept('GET', '**/api/classifications/*', firstClassification)
.as('firstClassification')
})
});
So in case, your data looks like this:
var data = [{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}]
So to extract the data with just curly braces you can do data[0].
{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}
Working example console screenshot:
Finally solved with:
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
}).as('classifications')
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
cy.intercept('GET', '**/api/classifications/*', (req) => {
const slicedClassifications = classificationsStub.slice(0, amount)
var selectedClassification = req.url.replace(new RegExp('.*api/classifications/'), '');
let foundClassification = FindChildClassification(selectedClassification, slicedClassifications);
//If not found return first always
req.reply({
statusCode: 200,
body: foundClassification ?? slicedClassifications[0]
})
})
}).as('classification')
And
export function FindChildClassification(id, classificationArray) {
for (let i = 0; classificationArray.length - 1 >= i; i++) {
if (classificationArray[i].id == id) {
return classificationArray[i];
} else {
if (classificationArray[i].childClassifications.length > 0) {
let childClassification = FindChildClassification(id, classificationArray[i].childClassifications);
if (childClassification != null) { return childClassification }
}
}
}
return null;
}

How to prevent repeating random numbers in Vue 3 and JavaScript

I am attempting to build a function that loops through a series of array objects containing names and ids after the array objects have been randomized, then returns a single filtered item to slots.value. So far, my spin function works in terms of looping through the randomized objects. However, the line const index = Math.floor(Math.random() * list.length) occasionally returns the same index number twice in a row. I wish to prevent the random index function from returning the same index number twice in a row. How can I do this?
const slots = ref([])
const names = ref([
{ name: 'Leslie', id: 1 },
{ name: `Ron`, id: 2 },
{ name: 'April', id: 3 },
{ name: 'Andy', id: 4 },
{ name: 'Tom', id: 5 },
{ name: 'Jerry', id: 6 },
])
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
const spin = async () => {
const list = names.value.sort(() => Math.random() - 0.5)
const newArray = []
for (let i = 0; i < list.length; i++) {
const index = Math.floor(Math.random() * list.length)
await sleep(100)
slots.value = list.filter(r => r.id === (index + 1))
}
}
One solution is to re-generate the index if the new value matches the previous one:
let prevIndex = null
const generateRandIndex = max => {
let index
do {
index = Math.floor(Math.random() * max)
} while (index === prevIndex)
prevIndex = index
return index
}
const spin = async () => {
⋮
for (let i = 0; i < list.length; i++) {
const index = generateRandIndex(list.length)
⋮
}
}
demo

Can the 'spread operator' replace an object with same uuid? Solution: Object.assing() [duplicate]

This question already has an answer here:
How to update an element of an array based on the index when using spread syntax? [duplicate]
(1 answer)
Closed last year.
I was trying to replace a property of an Object in an array with the spread syntax like this:
const origArray = [
{
"uuid":"first-team-uuid",
"name":"Team 1",
"players": [
"first-team-uuid"
]
},
{
"uuid":"second-team-uuid",
"name":"Team 2",
"players":[]
}
]
const doesNotWork = (prev, index, newName) => [...prev, {...prev[index], name: newName}]
const result1 = doesNotWork(origArray, 0, "Team3")
console.log(result1)
// # I know this works:
const doesWork = (prev, index, newName) => {
let old = [...prev]
old.splice(index, 1, {...prev[index], name: newName});
return old;
}
const result2 = doesWork(origArray, 0, "Team3")
console.log(result2)
I expect reslut1 to be like result2, but I seem to be wrong. I would like to write this in a singe line function and not with the workaround I currently have, if possible.
I can suggest these ways, through a filter, a map and an object.
But filter way changes the order of elements in array
const origArray = [
{"uuid":"c752cf08","name":"Team 1",},
{"uuid":"d46829db","name":"Team 2",},
{"uuid":"d46829d0","name":"Team 3",}];
const match = 1;
const name = 'Team 100';
//------------------------
const workWithFilter = (prev) =>
[...prev.filter((_, i) => i !== match), { ...prev[match], name }];
const result1 = workWithFilter(origArray);
console.log('workWithFilter:', result1);
//------------------------
const workWithMap = (prev) =>
prev.map((v, i) => (i === match) ? { ...v, name } : v);
const result3 = workWithMap(origArray);
console.log('workWithMap:', result3);
//------------------------
const workWithObject = (prev) =>
Object.assign([...prev], { [match]: { ...prev[match], name } });
const result4 = workWithObject(origArray);
console.log('workWithObject:', result4);
//------------------------
const doesWork = (prev) => {
let old = [...prev]
old.splice(match, 1, { ...prev[match], name });
return old;
}
const result2 = doesWork(origArray);
console.log('doesWork:', result2);
.as-console-wrapper {max-height: 100% !important; top: 0}

Javascript object not appending new attribute

I have this function, where I retrieve an array of objects, I then have a for loop to loop through the objects, and append an index or ind attribute to it:
module.exports.getCustomers = async (req, res) => {
let customers = await Customers.find({}, { "_id": 1 });
for (var i = 0; i < customers.length; i++) {
customers[i].ind = i;
}
console.log(customers)
}
but when I run this, the data is returned as
[
{ _id: ... },
{ _id: ... },
...
]
instead of:
[
{_id: ..., ind: 0},
{_id: ..., ind: 1},
...
]
Please how do I fix this
change your for and turn it into a map
module.exports.getCustomers = async (req, res) => {
let customers = await Customers.find({}, { "_id": 1 });
let mappedCustomers = customers.map((customer, index) => {
customer['ind'] = index;
return customer;
});
console.log(mappedCustomers);
return mappedCustomers;
}
or instead returning the customer, you can create a completly new customer.
let mappedCustomers = customers.map((customer, index) => {
return {...customer, ind: index};
});
It looks like your objects are freezed, idk what library you are using to fetch those items from your data source, but you can read about object freezing here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
Try copying the values over to the individual target objects with Object.assign.
module.exports.getCustomers = async(req, res) => {
let customers = await Customers.find({}, {
"_id": 1
});
for (var i = 0; i < customers.length; i++) {
Object.assign(customers[i], {
ind: i
});
}
console.log(customers);
}
I finally solved it. I think mongoose was messing with it. But adding ._doc seems to have fixed it
for (let i = 0; i < customers.length; i++) {
let customer = customers[i],
customer._doc = {
...customer._doc,
index: i
};
}

Categories

Resources