So this is a very simple question. Let's say we have an array of several objects. Then, with the usage of find function we select one object from array. If I change properties of that object, the changes are reflected in the array, as expected.
However, if I define a new variable with a different object and set it to the selected item from the array, the changes are not visible. E.g.:
let
arr = [
{
id: 1,
name: 'James',
prop: {
my: 'prop'
}
},
{
id:2,
name:'Delaney',
prop:
{
my:
'prop'
}
}
],
item = arr.find(x => x.id > 1),
newItem =
{
id: 3,
name:'test',
prop: {
my: 'test'
}
};
item = newItem;
console.log(newItem);
console.log(item);
console.log(arr);
Here I'd expect that since both item and newItem have the SAME value, the changes will be seen in arr as well, but it is not the case. If I change a single property on item, then the changes are visible. What gives?
A working example: http://jsbin.com/roxecofesa/1/edit?html,js,console
Imagine a variable item as a signpost. It points to where in memory is the object returned by the function arr.find(). Next you create another signpost newItem that points towards your newly created object.
When you write item = newItem you are saying: "Hey roadsign item, can you point towards the object that is currently pointed by newItem?"
Related
I am new to react. I have faced one issue and not able to solve it. I am looking for your help.
I have an array which I have listed below. All data are looped and displayed in the view. From my current array, I want to update the count of dietry array[] which is inside the fruits array.
This is my useState
const [foods, setFood] = useState(fruits)
if I console.log(foods) it gives data as below.
fruits: [
{
id: 1,
name: 'Banana',
family: 'abc',
price: 2.99,
isEnabled: true,
dietary: [
{
id:1,
disabled: false,
group: null,
selected: false,
text: 'N/A',
value: '858090000',
count:0
},
{
id:2,
disabled: true,
group: null,
selected: true,
text: 'N/A',
value: '80000',
count:0
},
}
This data are looped in a view page and there is onClick handleIncrement method which should increment the count of dietary array of index 0 or index1 etc whichever index sent from handleIncremnt() method.
This is my method
const handleIncrementCount = (dietary_index) => {
setFood(foods =>
foods.map((food,index) =>
dietary_index === food[index] ? {...food, qty:food.count+1}:food
)
);
}
I am not able to increase the count, in my view page counts are 0 even if i click the increment button.It shows some error within map
Any help is highly appreciated
I ma looking for a solutions
There are a few issues with your handleIncrementCount function. Firstly, you are trying to use the dietary_id parameter to find the correct food object to update, but you are using it to access the index property of the food object instead. This will always return undefined, and so the function will not be able to find the correct object to update.
Secondly, you are trying to update the qty property of the food object, but this property does not exist in the food object. Instead, you need to update the count property of the correct dietary object inside the food object.
Here is how you can fix these issues:
const handleIncrementCount = (dietary_id) => {
setFood(foods =>
foods.map(food => {
// Find the dietary object with the correct id
const dietary = food.dietary.find(d => d.id === dietary_id);
// If the dietary object was found, increment its count
if (dietary) {
dietary.count += 1;
}
// Return the updated food object
return food;
})
);
};
With this change, the handleIncrementCount function should be able to find the correct food object and update the count property of the correct dietary object.
Note that this function is using the Array.prototype.map() and Array.prototype.find() methods to transform the foods array and find the correct dietary object to update. These methods are commonly used in JavaScript to transform and find elements in arrays. It is worth reading up on these methods and understanding how they work in order to better understand this code.
I have an array object and I want to update the array object using id and props.
below is the structure of array object,
array object = [{columGrp:"All",deafultColumnName:"a",id:0},{columGrp:"ll",deafultColumnName:"ww",id:1},{columGrp:"oo",deafultColumnName:"qq",id:2},{columGrp:"qq",deafultColumnName:"ee",id:3}]
I have an editable table design and when a field changes I am passing field name, id, and changed value. based on that how can I update the object array.
const onChange=(props,value,id)=>{
//code here
}
onChange("columGrp","qwerty",1);
// result =>
array object = [{columGrp:"All",deafultColumnName:"a",id:0},{columGrp:"qwerty",deafultColumnName:"ww",id:1},{columGrp:"oo",deafultColumnName:"qq",id:2},{columGrp:"qq",deafultColumnName:"ee",id:3}]
a help would be really appreciable.
You can find the object by id from your array of objects using the filter function. If the object exists, you then change the given property, passing the given value. Objects work by reference in javascript so any changes in the found object will affect your object inside your array too.
const objectsArray = [{
columGrp: "All",
deafultColumnName: "a",
id: 0
}, {
columGrp: "ll",
deafultColumnName: "ww",
id: 1
}, {
columGrp: "oo",
deafultColumnName: "qq",
id: 2
}, {
columGrp: "qq",
deafultColumnName: "ee",
id: 3
}];
const onChange = (props, value, id) => {
const obj = objectsArray.find(x => x.id === id);
if (obj) {
obj[props] = value;
}
}
onChange("columGrp", "qwerty", 1);
console.log(objectsArray)
I have a dialog component that has a student_list props and this dialog is being triggered by a watcher, So basically, in my main component when I increment variable dialog_watcher++, the dialog opens.
The student_list props contains data which looks like this:
student_list = [
{id: 1, name: 'John'},
{id: 2, name: 'Jane'},
{id: 3, name: 'Jake'},
{id: 4, name: 'Finn'},
]
Now in the Dialog component, In my watch:{} hook, I have a variable student_list_data where I assigned the value of the student_list props..
watch: {
let temp = this.student_list;
this.student_list_data = temp;
}
Now, in the Dialog component, I have a button where I splice some object in the student_list_data array.
_selectStudent(item) {
//remove the selected student from the array
const index = this.student_list_data.findIndex(obj => obj.id == item.id);
this.student_list_data.splice(index, 1);
//append the selected student to a new array
this.selected_student.push(item);
}
Now, when I inspect in my vue devtools, I noticed that not only the student_list_data are being spliced, but also the student_list props. I checked everywhere but I dont have any function that splices data to student_list props.
Any idea where I went wrong?
When the non-primitive variables are assigned using "=", the reference will also be copied. This may lead to the mutation for all the variables that a particular object is assigned to.
Try the following.
You can use JSON.stringify to convert it to string and then parse into JSON.parse.
this.student_list_data = JSON.parse(JSON.stringify(this.student_list));
You can use spread operator.
this.student_list_data = [...this.student_list_data]
You are cloning the student_list wrongly. Try with this.
watch: {
this.student_list_data = [... this.student_list];
}
I have a State of objects in an Array (in my Redux Reducer).
const initialState = {
items: [
{ id: 1, dish: "General Chicken", price: 12.1, quantity: 0 },
{ id: 2, dish: "Chicken & Broccoli", price: 10.76, quantity: 0 },
{ id: 3, dish: "Mandaran Combination", price: 15.25, quantity: 0 },
{ id: 4, dish: "Szechuan Chicken", price: 9.5, quantity: 0 }
],
addedItems: [],
total: 0
};
I have an action to add 1 to the quantity of an object, such as
{id:1, dish: Generals Chicken, price: 10.76, quantity:0}
when a button in clicked in Cart.jsx. Here's the first Reducer I tried using the spread operator:
case "ADD_QUANTITY":
let existing_item = state.addedItems.find(
item => action.payload === item.id
);
return {
...state,
addedItems: [
...state.addedItems,
{ ...existing_item, quantity: existing_item.quantity + 1 }
]
};
This didn't work, instead of adding 1 to the quantity, it added another object with the quantity set to 2. . .So, I tried using Map like this
case "ADD_QUANTITY":
return {
...state,
addedItems: state.addedItems.map(item =>
item.id === action.payload
? { ...item, quantity: item.quantity + 1 }
: item
)
};
And this worked correctly. My question is, why didn't the spread operator work? As far as I can tell, it should do the same thing as the Map?
The two pieces of code are quite different.
The first one creates a new array out of state.addedItems and the new object { ...existing_item, quantity: existing_item.quantity + 1 }, and then assigns that array to the addedItems property of the state.
The second piece of code iterates addedItems and if it finds an element with the same id as the payload, it creates a new object { ...item, quantity: item.quantity + 1 } and returns that one, instead of the original item from the array.
Thus, even though both approaches create a new array, the first one has an extra object compared to the original, while the second has an object with a modified property.
The spread syntax, when used in an array literal context, does not reproduce the keys (the indexes), but just the values. As opposed to the spread syntax in an object literal context, which produces key/value pairs. The latter allows previous entries to be overruled by a new entry, having the same key, but the first does not have this behaviour: it always spreads all values without regards for indexes.
When replacing an element in an array, while copying it, you need to:
know the index at which the substitution should be performed, and
ensure that the copy is an instance of Array, and not just a plain object
You can use findIndex and Object.assign([], ) for addressing those needs:
case "ADD_QUANTITY":
let index = state.addedItems.findIndex(
item => action.payload === item.id
);
existing_item = state.addedItems[index];
return {
...state,
addedItems: Object.assign([], state.addedItems, {
[index]: { ...existing_item, quantity: existing_item.quantity + 1 }
})
}
Its because in your spread example, its has no way to tell which object it should overwrite. So it doesn't operate quite the same as some other examples you might see. Consider the following:
If you had an object like this:
let test = { a: 'first', b: 'second' }
Then doing spread like this would work:
let newTest = {...test, b: 'third' }
The reason is you are specifying that b should be overwritten.
When you try to create the same effect with an array of objects, you can't specify the key. So what you're actually doing is just appending the new object to the end of the array.
In the map example, you are checking the object contents and returning a different object based on if it matches your condition, so you know which object to overwrite.
So I have the following object structure:
const SamplePalette = {
id: 1,
name: "Sample Palette",
description: "this is a short description",
swatches: [
{
val: "#FF6245",
tints: ["#FFE0DB", "#FFA797"],
shades: ["#751408", "#C33F27"]
},
{
val: "#FFFDA4",
tints: ["#FFFFE1"],
shades: ["#CCCB83"]
},
{
val: "#BFE8A3",
tints: ["#E7FFD7"],
shades: ["#95B77E"]
}
]
}
Let's imagine that this object is managed by the state of my app like this:
this.state = {
currentPalette: SamplePalette,
}
My question is how would I go about updating the val property of a given swatch object in the swatches array? Or more generally - how do I only update pieces of this object?
I tried using the update helper as well as to figure out how Object.assign() works, however I've been unsuccessful and frankly can't really grasp the syntax by just looking at examples.
Also, since I'm going to be modifying this object quite a lot, should I look into maybe using Redux?
[EDIT]
I tried #maxim.sh suggestion but with no success:
this.setState(
{ currentPalette: {...this.state.currentPalette,
swatches[0].val: newValue}
})
Consider you have new new_swatches
I think the clearer way is to get array, update it and put back as:
let new_swatches = this.state.currentPalette.swatches;
new_swatches[0].val = newValue;
this.setState(
{ currentPalette:
{ ...this.state.currentPalette, swatches: new_swatches }
});
Also you have : Immutability Helpers or https://github.com/kolodny/immutability-helper
Available Commands
{$push: array} push() all the items in array on the target.
{$unshift: array} unshift() all the items in array on the target.
{$splice: array of arrays} for each item in arrays call splice() on the target with the parameters provided by the item.
{$set: any} replace the target entirely.
{$merge: object} merge the keys of object with the target.
{$apply: function} passes in the current value to the function and updates it with the new returned value.