If the object is currently in the array I want to update some value, and if it's not I want to add it to the array. This is the solution I have below, which I don't feel is the best/correct way to do it.
const handleAddToCart = product => {
const newList = [...cart]
if (!newList.includes(product)) {
newList.push(product)
} else {
const productIndex = newList.findIndex((obj => obj._id === product._id))
newList[productIndex].prop = "Some value"
}
setCart(newList)
}
Thank you.
You have to be pretty careful here, as there are a few gotchas with object comparison and mutating the state ([...cart] is not sufficient in deep copying cart). You can update the state in a pure fashion as follows, although I would recommend something like Redux for complex state management.
const handleAddToCart = product => {
const index = cart.findIndex(obj => obj._id === product._id)
if (index === -1) {
setCart(cart.concat(product))
} else {
setCart([
...cart.slice(0, index),
Object.assign({}, product, { prop: "Some value" }),
...cart.slice(index + 1),
])
}
}
const handleAddToCart = productToAdd => {
const newList = [...cart];
const existent = newList.find(product => product.id === productToAdd.id);
if(existent) {
existent.prop = "prop";
} else {
newList.push(productToAdd);
}
setCart(newList);
}
Related
I need help to see if I can improve this code that I have, first I describe the final result that I hope and maybe this way you can find how to improve a little this useEffect:
I need to receive that data object, compare it with one previously stored in localstorage, and compare them to see if there is any new record in that object, if it finds new data, extract them, add the isNew property only to those key that found new and create a new array with the data I received and newArray that includes the modified data.
const localStorageKey = 'laboratoryData'
const oldData = localStorage.getItem(localStorageKey)
useEffect(() => {
if (data) {
if ([null, undefined].includes(oldData)) {
localStorage.setItem(localStorageKey, JSON.stringify(data.data))
} else {
const arrayIsEqual = (data, oldData) => {
data.data === oldData ||
(data.data.length === oldData.length &&
data.data.every(
(f, i) => f.id === oldData[i].id && f.name === oldData[i].name,
))
}
if (arrayIsEqual) {
localStorage.setItem(localStorageKey, JSON.stringify(data.data))
} else {
const diff = data.data
.filter((x) => !oldData.includes(x))
.concat(oldData.filter((x) => !data.data.includes(x)))
const newArray = diff.map((obj) => ({...obj, isNew: 'true'}))
const finalArray = {...data, ...newArray}
localStorage.setItem(localStorageKey, JSON.stringify(finalArray))
}
}
}
}, [data])
Maybe i`m duplicating some code or missing a custom hook with a better performance
Thanks!
without seeing your data and based on your code snippet, hopefully your data.data and oldData are always be arrays of objects that have always have key id and name.
const localStorageKey = 'laboratoryData';
const oldData = localStorage.getItem(localStorageKey);
useEffect(() => {
if (!data) return;
if (!oldData) {
localStorage.setItem(localStorageKey, JSON.stringify(data.data));
return;
}
if (data.data.length === oldData.length && data.data.every((d, i) => d.id === oldData[i].id && d.name === oldData[i].name)) return;
const newData = data.data.filter(d => oldData.findIndex(od => od.id === d.id && od.name === d.name) === -1).map(d => d["isNew"] = true);
const finalArray = oldData.map(od => od["isNew"] = false).concat(newData);
localStorage.setItem(localStorageKey, JSON.stringify(finalArray));
}, [data])
I have a small problem,
I get my ref object from that method
const dataAnimals = ref([])
function getDataAnimals() {
axios.get('/json/data_animal.json').then((response) => {
dataAnimals.value = response.data
})
}
getDataAnimals()
And i want to use another method using that ref object :
function countAnimal(type) {
dataAnimals.forEach((item) => {
if (animal.animal == type) {
total_hen += dataMint.value[animal.template_id]
}
return total_hen
})
}
const totalHen = countAnimal('hen')
But i can't iterate through :
dataAnimals.value.forEach((item) => {
Is there anyway to make that work ?
Thank you :)
As the response is an object and not an array, you cannot iterate over it with forEach, you need to use Object.entries()
function countAnimal(type) {
let total = 0;
for (const [key, item] of Object.entries(dataAnimals)) {
if (item.animal === type) {
total++;
}
}
return total;
}
const totalHen = countAnimal('hen');
And I would use a reactive object:
const dataAnimals = ref(null);
function getDataAnimals() {
axios.get('/json/data_animal.json').then((response) => {
dataAnimals.value = response.data
});
}
getDataAnimals()
Of course if you want that count to be reactive as well you'd need to use a computed property.
I'm currently building an app using vue.js and firebase as backend and I'm checking whether a value already exists in the database by doing so:
addItem ({commit}, payload) {
const footprint = payload.footprint
firebase.database().ref('ecologic/footprint').once('value', snapshot => {
const obj = snapshot.val()
let objExists
for (let key in obj) {
if (obj[key] === footprint) objExists = true
else objExists = false
}
if (!objExists) {
firebase.database().ref(`ecologic/footprint`).push(footprint)
}
})
},
How can I extend this functionality to compare an array's value with another array and post to firebase if the value doesn't exists yet.
I tried to use double loop but was not working since I'm using a boolean. Is there a nicer way to do it? Thank you
I tried another way but this time console.log is always returning true
firebase.database().ref('ecologic/footprint').once('value', snapshot => {
const objSnap = snapshot.val()
const loadedFootp = []
for (let key in objSnap) {
loadedFootp.push(objSnap[key])
}
for (let obj in footprint) {
const newFootp = footprint[obj]
const objExists = footprint.some((newFootp) => loadedFootp.indexOf(newFootp) !== -1);
console.log(objExists)
}
})
Found a way by doing so:
firebase.database().ref('ecologic/footprint').once('value', snapshot => {
const objSnap = snapshot.val()
const loadedFootp = []
for (let key in objSnap) {
loadedFootp.push(objSnap[key])
}
for (let obj in footprint) {
if (loadedFootp.some(item => item === footprint[obj])) {
} else {
console.log(footprint[obj])
}
}
})
The function below receiving a rating value inside an object. While ID or Question stay intact, the rating value can be updated. As a result a React state value should be updated.
Is there a way to make this function look prettier/concise while just using a vanilla javascript.
ratingCompleted = ({ rating, question, id }) => {
let array = this.state.ratingResponses;
const index = array.findIndex(elem => elem.id == id);
if (index === -1) {
array.push({ rating, question, id });
this.setState({ ratingResponses: array });
} else {
array.map(object => {
if (object.id === id) {
object.rating = rating;
return object;
} else {
return object;
}
});
this.setState({ ratingResponses: array });
}
};
Make sure you spread to stop mutations
This could be a little cleaner but i thought I would show each step.
const array = [...this.state.ratingResponses]; // spread this so as to make a copy
let updatedArray;
const hasRatingAlready = array.some(item => item.id === id);
if (!hasRatingAlready) {
updatedArray = [...array, { rating, question, id }];
} else {
updatedArray = array.map(item => item.id === id ? {...item, rating} : item);
}
this.setState({ ratingResponses: updatedArray });
I'm following a react tutorial but I'm lost. I don't understand starting line 9.
so I tried to make a little miarature
const updateTodo = (list, updated) => {
const index = list.findIndex(item => item.id === updated.id)
return [
...list.slice(0,index),
updated,
...list.slice(index+1)
]
}
https://jsbin.com/sifihocija/2/edit?js,console but failed to produce the result that the author did, what's wrong?
Issue is in this line:
const index = list.findIndex(item => item.id === updated.id)
updated is an array, to access the id, you need to specify the index also,
for other array you are using loop, so item will be the each object of the array, and item.id will give you the id of each object, try this:
const index = list.findIndex(item => item.id === updated[0].id)
const arr = [
{id:1,name:'hello'},
{id:2,name:'hai'}
]
const arr2 = [
{id:2,name:'this should be a new string'}
]
const updateTodo = (list, updated) => {
const index = list.findIndex(item => item.id === updated[0].id);
return [
...list.slice(0,index),
...updated,
...list.slice(index+1)
]
}
console.log(JSON.stringify(updateTodo(arr,arr2)))
Check the working code: https://jsbin.com/pazakujava/edit?js,console
Let me know if you need any help in this.
It's simpler and cleaner using Array.map:
const updateTodo = (list, updated) =>
list.map((item) => {
if (item.id !== updated.id) {
return item;
}
return updated;
});