How to fix state change in VUEX? - javascript

I have a problem with changing state while splicing element from another array then changes in state. TO be clear, i don't want state to change, just want to splice one element from array arrayWithFilters = []
export const SHOW_RESULTS_WHEN_NOTHING = (state) => {
let selectedFilters = {...state.selected.filters},
arrayWithFilters = []; //Making splice from this array, but it also removes from state.selected.filters.
for (let filter in selectedFilters) {
arrayWithFilters.push(selectedFilters[filter])
}
arrayWithFilters.forEach((filter) => {
if (filter.values.includes('qcontrast')) {
filter.values.splice('qcolor', 1);
console.log(filter)
}
})
}

problem solved with the next code
export const SHOW_RESULTS_WHEN_NOTHING = (state) => {
let selectedFilters = {...state.selected.filters},
arrayWithFilters = [];
let selectedFiltersCopy = JSON.parse(JSON.stringify(selectedFilters));
arrayWithFilters = Object.values(selectedFiltersCopy);
arrayWithFilters.forEach((filter) => {
if (filter.values.includes('qcontrast')) {
filter.values.splice('qcontrast', 1);
}
})
console.log(arrayWithFilters)
}

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) {
}

How can I update individual elements of an array using state hook?

This is the section of code I am dealing with,
This is my hook
const [array, setArray] = useState(
JSON.parse(localStorage.getItem("notes")) ?? []
);
And this is the function,
const save = () => {
let info = one.current.value;
console.log(newIndex, " and ", info);
console.log("this si array element -> ", array[newIndex - 1]);
array[newIndex - 1] = info;
if (newIndex !== undefined) {
setArray((e) => {
return e.map((e1, i) => {
if (i + 1 === newIndex) {
return [...e ];
}
});
});
}
};
info has the correct input I want to update to and newIndex have the index of the element I wish to update.
Can you suggest to me what I need to change in this section, this is part of the above function,
setArray((e) => {
return e.map((e1, i) => {
if (i + 1 === newIndex) {
return [...e ];
}
});
To update your array you do not need to map anything. You only need to copy the array, modify the copied array at the right index and return the copied array. React will take care of the rest.
It's important, that you copy the array, else react won't notice the change. useState only remembers the array's address in memory.. Only through a new array with a new address will useState actually fire.
Here is my take on what I think your save() function should look like:
const save = () => {
let info = one.current.value;
if (newIndex !== undefined) {
console.log(newIndex, " and ", info);
console.log("this is array element -> ", array[newIndex - 1]);
setArray((e) => {
let temp = [...e];
temp[newIndex - 1] = info;
return temp;
});
}
};
Tried the code in codesandbox and I think this is what you want.

Increment value of array of objects redux

I need to increment quantity of item in cart if item already exists in the state array. In the reducer I got it to work but it needs to be immutable. Because of this, my component doesnt update properly.
This is the code for my reducer:
import { ADD_TO_CART, REMOVE_FROM_CART } from '../actions/types';
const initialState = [];
//Cannot mutate array in reducer
export default function(state = initialState, action){
const { type, payload } = action;
switch(type){
case ADD_TO_CART:
const newState = [...state]
for(var i = 0; i < newState.length; i++){
if(newState[i].item.uid === payload.item.uid){
newState[i].item.qty ++;
return [...newState];
}
}
return [...state, payload];
case REMOVE_FROM_CART:
for(var j = 0; j < state.length; j++){
if(state[j].item.uid === payload.uid){
state[j].item.qty = 1;
}
}
return state.filter(cartItem => cartItem.item.uid !== payload.uid);
default:
return state;
}
}
I need to increment qty if item is already in the array.
The issue I see is with newState[i].item.qty++;, that although you shallowly copied the array, the elements in the array still represent those of the previous state, so post incrementing it mutates the object.
To resolve this issue you should also copy each item into a new object, then update the new object reference.
The following also include a minor optimization to iterate the data once versus twice, by checking for the matching item ID as it copying the state into a new array.
let itemExists = false;
const newState = state.map(item => {
const newItem = { ...item };
if (newItem.item.uid === payload.item.uid) {
itemExists = true;
newItem.item.qty = item.qty + 1;
}
return newItem;
});
if (!itemExists) newState.push(payload);
return newState;
EDIT: Alternative method
const itemIndex = state.findIndex(item => item.item.id === payload.item.id);
if (itemIndex !== -1) {
return state.map((item, i) => ({
...item,
item: {
...item.item,
qty: item.item.qty + (itemIndex === i ? 1 : 0),
}
}));
} else {
return [...state, payload];
}

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