managing array prop in react - javascript

I've a react application, and i've found a bug where i'm filtering an array for searching the current item the user has selected and then i'm going to do stuff with it...but, didn't know that filter function return a reference to the array's item, so, every change i made to the selected item i'm doing the same to the prop array.
const pippo = maledettoArray.filter(item => item.id === idInfame)[0];
How can i filter the prop array to get the specific item without changing it?

You can use find method instead of filter which returns first match and exits the loop.
const pippo = maledettoArray.find(item => item.id === idInfame)
To create shallow copy of the object you can use Object.assign or spread syntax.
const clone = {...pipo}
If you want to create deep copy of the nested object then you could use Lodash _.cloneDeep(value) method.

First of all, I would recommend you use the find function instead of filter to avoid the empty array return and undefined at [0]
Secondly, yes, the object reference would be returned. To avoid this, you can use Object.assign({}, originalObject) or using the spread syntax {...originalObject} . A potential problem would be with nested objects which could still be a problem.
Probably this article can help you in such case https://medium.com/#Farzad_YZ/3-ways-to-clone-objects-in-javascript-f752d148054d

Related

Why push does not working with set methond in Map object

So very quick question here which I wasn't able to get sorted when searching google.
I have some code that works which has a Map object this.tweet and a (key,value) of (string,array). I push a value into the array and re-set Map object.
const newTweet = this.tweet.get(tweetName) || [];
newTweet.push(time);
this.tweet.set(tweetName, newTweet);
However, I am a minimalist freak and want a one-liner. When I want to add something to the array, I was wondering why I am not able to do this
this.tweet.set(tweetName, newTweet.push(time));
I keep getting a newTweet.push(time) is not a function error.
Thanks
Look at some documentation for push
The push() method adds one or more elements to the end of an array and returns the new length of the array.
Since you want to pass the array to set you can't use the return value of push.
You could create a completely new array instead:
const newTweet = this.tweet.get(tweetName) || [];
this.tweet.set(tweetName, [...newTweet, time]);

Can changing the array length directly produce bugs?

I have an app where the redux state has a field called data that's null initially, then when uploading something it changes to an array of objects and the reducer uses delete to remove an object when we press the required button. But that doesn't change the length of the array so it causes an uncaught error. The simplest solution would be to simply change the length of the array after we delete that object. Can this produce any bugs?
EDIT: This is the code:
case actions.RIR:
const filtered = [...state.data];
delete filtered[action.payload];
filtered.length--; // this has been added by me
return {...state, data: [...filtered]};
The original code isn't mine. It's part of a project. I've been asked to fix an error.
First one foremost, reducers should be pure - meaning - no side effects.
delete is a side effect since it mutates an original object.
In reducers, use immutable patterns - either use filter, or splice a copy of the original array (less recomended).
Besides that, delete will simply make this element undefined, and your array will look like:
['item 1','item 2'....,empty,'item n']
I would write it:
case actions.RIR:
const filtered = state.data.filter(item => item !== action.payload);
return {...state, data: filtered};
Or whatever filter logic you might require.

javascript: Update property value in Array() with index as parameter

Currently I've a react function that removes from a Array called rents the current rent perfect. The issue is that I need to update the rent row value called status and set property from 1 to 4 the code below works. I don't seem to get how to get the Index of rent to be able to update it.
removeItem (itemIndex) {
this.state.rents.splice(itemIndex, 1) // removes the element
this.setState({rents: this.state.rents}) // sets again the array without the value to the rent prop
console.log(itemIndex) // itemIndex
}
currently I'm adding this to the code to debug but get this error
console.log(this.state.rents[itemIndex].unique_key)
Stack Trace
TypeError: Cannot read property 'unique_key' of undefined
I need to be able to update the rent property value called status from 1 to 4 and setState again
To elaborate the comments, starting first with the most important:
Like #devserkan said, you should never mutate your state (and props), otherwise you start to see some really weird hard-to-make-sense bugs. When manipulating state, always create a copy of it. You can read more here.
Now for your question:
this.setState is asynchronous, so to get your state's updated value you should use a callback function
const rents = [...this.state.rents]; // create a copy
rents.splice(itemIndex, 1);
this.setState({ rents }, () => {
console.log(this.state.rents); // this will be up-to-date
});
console.log(this.state.rents); // this won't
Personally, I like using the filter method to remove items from the state and want to give an alternative solution. As we tried to explain in the comments and #Thiago Loddi's answer, you shouldn't mutate your state like this.
For arrays, use methods like map, filter, slice, concat to create new ones according to the situation. You can also use spread syntax to shallow copy your array. Then set your state using this new one. For objects, you can use Object.assign or spread syntax again to create new ones.
A warning, spread syntax and Object.assign creates shallow copies. If you mutate a nested property of this newly created object, you will mutate the original one. Just keep in mind, for this situation you need a deep copy or you should change the object again without mutating it somehow.
Here is the alternative solution with filter.
removeItem = itemIndex => {
const newRents = this.state.rents.filter((_, index) => index !== itemIndex);
this.setState({ rents: newRents });
};
If you want to log this new state, you can use a callback to setState but personally, I like to log the state in the render method. So here is one more alternative :)
render() {
console.log( this.state.rents );
...
}

Filter an object array based on the property

The data I have stored is in a 2d Array.
One element of looks like below. (not an assignment operator)
someObjArray[5] === [{lastname:"foo", firstname:"bar", grade:10, userId:"foobar1234"},...]
For the particular above variable I want to filter on userId
I am attempting to do so like this.
var test = stuArray[5].filter(function(item) {
return item['userId'];
});
Resulting in:
test === [{lastname:"foo", firstname:"bar", grade:10, userId:"foobar1234"},...]
Where the desired results are
test === ["foobar1234",...]
I have also tried using a dot operator with the same results.
I don't think filter is what you're looking for here.
The function (non-anonymous in your case but you can also use anonymous functions) that you are passing into your filter method needs to return a true or a false. This is how the method "filters" your array - it gives you back an array whose elements pass the filter, or return true when passed as arguments into filter's function.
Note that this does not change the original array.
What you should use instead is the very similar map() function.
Note that map(), just like filter(), does not change the original array.
You can do it like this:
var someObjArray = [{lastname:"foo", firstname:"bar", grade:10, userId:"foobar1234"}];
console.log(someObjArray.map(s => s.userId));
Online demo (jsFiddle)

this.state.something mutated and caused issue

For some reason I can't do this
this.state.something.map(obj => obj.id)
because it caused extra rerendering. How to get something from state, without assign it to a new variable?
I used to do this ugly hack
something_state_holder = this.state.something
something_state_holder.map(obj => obj.id)
but is there any better / more elegant way?
As #mayank-shukla said, what you are doing here is perfectly valid. The map() method iterates through an array and returns and array, but without mutating the iterated one. Here's what the MDN documentation says:
The map() method creates a new array with the results of calling a provided function on every element in this array.
map does not mutate the array on which it is called (although callback, if invoked, may do so).
However, should you want to make a shallow copy on an array, you could use slice:
something_state_holder = this.state.something.slice();
var resulting_array = something_state_holder.map(obj => obj.id);
This iterates through the copy, and not the state. What you did is not creating an array, you are simply assigning the reference to the same array to a new variable. So mutating that will mutate the state.

Categories