How to check if object is in Mobx observable array? - reactjs

I'm using indexOf in a React component to style a button based on whether an object is in an mobx observable array.
The button is for favoriting. It pushes the object for that specific list item into an observable array in the store called 'favorites'. favorites is an observable array of objects.
Here's the ES6 template literal from my button:
className={`btn-group ${((this.props.store.favorites.indexOf(this.props.data) > -1)) ? 'success' : 'info'}`}
Basically, it's a check for if the object is in the array, className will be success, if false info.
This works perfectly fine when the favorites array is in local state. But I get that the objects within the favorites array look differently once they are in the observable array. I get that the observable array favorites is different than a local array favorites.
But how do I do a test for whether an object is in an observable array of objects? I tried slice() and peek() and using the findIndex but no dice.

Regarding the doc: isObservableArray
Returns true if the given object is an array that was made observable using mobx.observable(array).
So to know if data is in an observable favorites array:
// If data is a primitive
className={`btn-group ${mobx.isObservableArray(this.props.store.favorites) && this.props.store.favorites.indexOf(this.props.data) > -1 ? 'success' : 'info'}`}
// Id data is an object it is a little more verbose and coupled to your data
// structure. You have to use the `find` function to iterate and test if an
// element in the array has the same id.
className={`btn-group ${mobx.isObservableArray(this.props.store.favorites) && !!this.props.store.favorites.find(fav => fav.id === this.props.data.id) ? 'success' : 'info'}`}
Here is a POC with a function helper: https://jsbin.com/botijom/edit?js,console

Michel (mobx creator) gave me the hint I needed via the Gitter channel.
I actually needed a shallowly observable array, not a deeply observable one. I don't need each and every property of the objects in the array to be observable (hence all the sets/gets on the object properties I was seeing before), just whether an object is added or removed.
So I changed it from
#observable favorites = []
to
#observable favorites = observable.shallowArray();
Ultimately, though #dagatsoin 's answer is right if you need to use a deeply observable array.

Related

How to prevent a render when filtering redux state object from an array of objects?

I have the following line that targets an object located in an array of objects, the end point of the array is subjected to changes (dispatch actions) the issue is when a change made the whole component re-renders this issue is present when .... there is an array but, if am accessing a part of an object directly rather than filtering an object from an array of object then this won't happen an workout around this ?
const mainGroups = useAppSelector((state) => state.global.weeks[clientId].filter((week) => week.weekId === currentWeekAtHand)[0].mainGroups[id]);

vueJs updating props even though i am method variable

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

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.

Access elements of an Observable Array

I have a prop named blockers that returns an observable array of objects. These objects contain 'userId.'
How can I go about returning an array that contains these userIds?
Computed observables can help with situations like these. Make sure that your component is decorated as a mobx-react #observer, that way it will automatically make props observable.
#computed get userIds () {
return this.props.blockers.map(blocker => blocker.userId)
}

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