vueJs updating props even though i am method variable - arrays

I have the following method compares two array, one coming from the props and the other one from my own component. Every element that exists in my props array but doesnt exist in my components array is inserted in a third array with the added property called "destroy : true" so i can send it to the back end to be deleted from the database.
However for whatever reason my props is being updated instead of the variables i use in the method to do all this. i am not really sure why since i am not referencing the prop directly but i do copy its content to the variables in the method.
updateArray(){
let updatedArray = []
let oldArray = [...this.props.array]
oldArray.forEach(element => {
if(this.componentArray.indexOf(element) > -1){
updatedArray.push(element)
}else{
let newElement = element
newElement.destroy = true
updatedArray.push(newElement)
}
})
return updatedArray
},
why does this happen exactly? every other element in my component works fine except this.

Yes, you are copying the elements of the this.props.array array into a new array local to the method but given that the elements of the array are objects, both arrays are in the end containing same objects (references to the objects)
You can create shallow copy of the original element with the spread operator let newElement = { ...element } - this creates the completely new object and copy all properties of the original object. But be aware that if any property of original objects contains array/object, you have the same problem... just one level down

Related

How to iterate through an array of objects and return one that has a specific object ID using JSX (in mapStateToProps of React-Redux)

I am trying to pass an object (called a lecture) to the props from state using mapStateToProps. The object exists in an array of objects. I believe I am making a syntax error but am uncertain on exactly what is the correct syntax should be because the code below works for cycling through a parent object (that contains objects inside of it) and select the correct object inside of the parent.
//This code works to cycle through a parent Object that contains objects inside of it; returning the object inside that has the correct ID.
//It doesn't work in this situation ... where instead of having objects inside a parent object,
//there are obejcts inside a parent Array.
const mapStateToProps = (state) => {
const lectureID = state.selectedLectureID;
console.log(lectureID); <--- THIS SHOWS THE CORRECT ID OF THE OBJECT I AM TRYING TO READ.
const lectures = state.firestore.ordered.lectures;
console.log(lectures); <------ THIS SHOWS THE ARRAY OF OBJECTS, INCLUDING ONE OBJECT THAT HAS THE LECTURE ID FOUND ABOVE
const selectedLecture= lectures ? lectures[lectureID] : null; <--- ERROR HERE... TRYING TO CYCLE THROUGH THE ARRAY OF LECTURES AND PASS THE LECTURE THAT HAS THE CORRECT LECTURE ID. IF NONE HAVE THIS ID, THEN IT SHOULD RETURN "null".
console.log(selectedLecture); <--- THIS RETURNS "undefined", SUGGESTING THE CODE ABOVE DIDN'T READ THROUGH THE ARRAY OF OBJECTS AND SELECT THE ONE WITH THE CORRECT ID.
return {
selectedLecture: selectedLecture,
}
}
NOTE: The code above appears interpret the lectureID as an index in the array rather than an attempt to identify the objects ID within the array of Objects. How can I correct this?
I FOUND AN ALTERNATIVE SOLUTION:
Instead of trying to iterate across the array of objects inside mapStateToProps, I found it easier to simply pass the object with the specific ID as an object through Actions + Reducers, and interacting with the content via the state.

React - State array deleting last item in array instead of specified index

I have an array state filled with objects called items:
const [items, setItems] = useState([{name: "", toppings: []}])
However when I try to delete a specified index with this function:
const removeItem = (index) => {
setItems(items.filter((item, i) => i !== index))
areItemsCompleted()
}
It works when I print the elements to the console outside of the function, however the item is not rendering properly. It only removes the last element of the array from the jsx but the items array has the correct values. I read somewhere that react only checks for changes in state shallowly so it does not check the content of the object it is deleting. However, I am unsure as to why it shows up in the console that items have the correct value but the components arent rendering the correct data. (Instead it renders the same data except for the last element in items).
I have tried multiple ways of deleting elements from my array such as
const removeItem = (index) => {
let arr = [...items]
arr.splice(index, 1)
setItems(arr)
areItemsCompleted()
}
How would I delete an element from my array full of objects and render the proper data?
So I was using the array index as the key prop of the component, but that doesn't work when deleting an item in the array.
React doesn't know which key to delete, as the array index will still exist even after that particular element has been deleted.
Solution
Use a unique key for each element in the array. Something like id which react can see has been deleted.
It's hard to guess;
Check, may be you are re-setting items somewhere later;
Plus functional form is safer:
setItems(lastItems=>lastItems.filter((item, i) => i !== index))

update nested Array state reactjs

Unable to handle nested array in react state, here what I am trying I need to push value in this.state.form.contentFormArr
let langulageform, contentObj,contentFormArr;
contentObj={heading:'',subheading:''};
contentFormArr=[this.contentObj]
langulageform =[
{key:"Ar",lang:"Arabic",contentFormArr:this.contentFormArr},
{key:"En",lang:"English",contentFormArr:this.contentFormArr},
{key:"Ru",lang:"Russian",contentFormArr:this.contentFormArr},
{key:"Sp",lang:"Spanish",contentFormArr:this.contentFormArr},
{key:"Ve",lang:"Vetnamese",contentFormArr:this.contentFormArr}
];
constructor(){
super()
this.addContentArea = this.addContentArea.bind(this)
this.state={
form:this.langulageform
}
}
addContentArea(index){
this.setState((state)=>{
const contentformArr = [...state.form[index].contentFormArr,this.contentObj]
return{
...state.form.contentFormArr,
contentformArr
}
})
}
I made multiple forms by the iterating this.state.form array, Now I need when the user clicks on any form box button to add more field then it will push value in particular index array and then it will iterate more fields.
Well I did it but I think the way which I use is not good practice. First I made the correction on Array which I set to state as the initial value, because fore I was set array value to contentForm array when I made changes to them it set changes to everywhere on state Object.
langulageform =[
{key:"Ar",lang:"Arabic",contentFormArr:[{heading:'',subheading:''}]},
{key:"En",lang:"English",contentFormArr:[{heading:'',subheading:''}]},
{key:"Ru",lang:"Russian",contentFormArr:[{heading:'',subheading:''}]},
{key:"Sp",lang:"Spanish",contentFormArr:[{heading:'',subheading:''}]},
{key:"Ve",lang:"Vetnamese",contentFormArr:[{heading:'',subheading:''}]}
];
Secondly I create one blank array and push all values in it, so that I can push value in it, This can't be done in state because of immutable object, and after getting correct index object I made corrections and return the object.
addContentArea(index){
this.setState((state)=>{
let Arr=[];
state.form.map((e,i)=>{
Arr.push(e);
if(i===index){
Arr.contentFormArr.push({})
}
})
return{
Arr
}
})
}
I did it because I feel to deal with multidimensional immutable arrays are bit tricky this is not an optimized way but it works every time and I have checked that the react component lifecycle methods are also working fine with this.

Passing Array as Props in vue Modal

I want to pass array from one component to the other in vueJs, which i am able to do with
<add-new-admin-modal
:permissions = "permissions"
</add-new-admin-modal>
In my other component which is a modal actually,
I am receiving the props as,
props: {
permissions: {
type: Array,
default: () => []
}
}
Here when i try to change the permissions array, it reflects the parent data, As mentioned in the documentation.
https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
so i tried with spread operator
data () {
return {
statePermissions: [...this.permissions]
}
}
The statePermissions array is still empty when i try above method,
I even tried with Object.assign
data () {
return {
statePermissions: Object.assign([], this.permissions)
}
}
Still it doesn't work.
In my Modal, I am accessing it as
<div v-for = "permission in statePermissions" :key = "permission.id">
...someHtml here.
</div>
The main idea is, I have a component which gets the data through an api, then i have a modal which takes this data and updates it accordingly and submit it to an api.
when the modal is closed, the parent component should need to have the unedited data, so that if modal is reopened it should get unedited data.
In the process of using Modal, My parent component remains in the same state (It neither gets mounted nor changed), so their is no point in making the request for default data again from parent.
Your problem is probably that the default value for you prop is an empty array and you're assigning it to a local variable before the property is properly populated by the parent (or it might even be a lifecycle issue).
Try moving your assignment to the local variable to the mounted() hook or even better if you wan't it to be reactive watch your property:
watch: {
permissions(newValue) {
this.statePermissions = newValue
}
}
You also don't need to ...spread an array to assign it to an array.
Since permissions is an array of objects, when you make a copy of it, the resulting array is a shallow copy meaning it will contain the same references to objects. That's why modifying the new array's values update the old array's values as well. You need to create copies of the objects inside permissions.
If permissions only contains primitives, you can do something like this:
this.statePermissions = JSON.parse(JSON.stringify(this.permissions));
If permissions is of a certain type (i.e. new Permission()), you can map it (I think this is cleaner):
this.statePermissions = this.permissions.map(x => new Permission(x.propA, x.propB, etc.));
This way, each cloned object in statePermissions will have the same properties as the object it's copied from in permissions, but it's independent so modifications won't affect the parent it was created from.
There's a few other ways in this post.

How do I update/delete objects inside this.state array in React

So I have a React component where I have:
getInitialState: function () {
return {
peopleDetails: []
}
}
peopleDetails will contain objects which will have property names like name, email, phone etc.
Here's the problem: I'll be passing methods to child components which should mutate the objects of this array. Some methods will just edit a person's email, another will edit the phone etc. Thus, they'll need to call setState.
As far as I understand, setState should return a new copy of the object. I find this impossible to do because things are difficult enough even if I have to mutate the object (I'll have to specify some filters to find it inside an array, then change its value etc).
I'm pretty sure a lot of React apps use data structures like these...where in the state you have an array holding objects and you'll need to do stuff to those objects. Is there some easy way to accomplish this, respecting the "rule" that each setState invocation should return a completely new state object?
If you really don't want to use immutable data, then you can directly mutate the properties you like and invoke a this.forceUpdate() instead of setState after mutations have occurred.
If you were to proceed with immutable data, then adding to that array would return a new array containing the new object. If you removed that person, you'd then return a new empty array. If you were to modify an item in-place in the array, then you'd build a new array using concat/slice to get all elements that haven't changed, then add your changed element, then add everything after the changed element's index.
For a more in-depth discussion on avoiding array mutations, check out this talk.

Resources