Swapping two objects in array: ReactJS - javascript

I asked myself if there is a clean, proper way to swap two objects in an array using setState. This is what I currently do:
export function moveStepUp(index) {
if(index > 0){
let currentStep = this.state.stepsData[index];
let stepAbove = this.state.stepsData[index - 1];
this.setState((prevState) => ({
stepsData: prevState.stepsData.map((step, i) => {
if(i === index - 1)
return {
...currentStep,
position: i
};
if(i === index)
return {
...stepAbove,
position: i
};
return step;
})
}), () => console.log(this.state.stepsData));
}
}
This code is working, but I thought there might be a better solution. It seems like too much lines of code for such a simple task. Thanks!

Why not simply swapping two array values by using a third variable if you know the element index.
First copy the array in another variable, swap two array values, then use setState to update the state value.
Like this:
this.setState(prevState => {
let data = [...prevState.data];
let temp = data[index-1];
data[index-1] = data[index];
data[index] = temp;
return { data };
})
Instead of spread operator, you can use any other way to create a copy of array.

In react hooks
you can use this, this works for me
const [array,setArray]= useState([]);
setArray(array => {
let data = [...array];
let temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
console.log(data);
return data ;
})

Related

How can I add a string to a string value inside an object?

What im trying to do is to add a string id next to a value inside of an object.
So the object is like this:
["John","Mike"]
An item in the object is generated as soon the user clicks an add button
const handleAddClick = () => {
setLanguage([...language, ""]);
};
const handleItemChanged = (event, index) => {
const value = event.target.value;
const list = [...subtitle];
if (list.filter((f) => f === value).length > 0) {
setErrorValidation("Names cannot be equal!");
} else {
setErrorValidation("");
}
list[index] = value;
setName(list)
};
In the handleItemChanged, I tried to do this, but it didn't work.
let string = "test"
list[index] = value + string;
setName(list)
So what I want is to add a string to a new value that is added to the list
["Johntest", "Miketest"]
How can I solve this?
You can use map before assigning value:
// ... the other code is omitted for the brevity
list.map(item => item + "test")
setName(list)
An example:
let arr = ["John", "Mike"]
arr = arr.map(item => item + " test")
console.log(arr)
Calling setName(list) does not trigger a rerender for the simple reason that list is still the same object. setState will only work if the previous and new value is different. For objects, they are shallowly compared.
That is why it is suggested to create a new array using .map():
let string = "test"
const newList = list.map(e => e+urString)
setName(newList)

React - Deleting rest of the array instead of just one item

Here's the link:
https://codesandbox.io/s/heuristic-heisenberg-9cxb9
I have this method: deleteItem
This code:
return {
monsters: prevState.monsters
.slice(0, deleteItemPosition)
.concat(
prevState.monsters.slice(
deleteItemPosition + 1,
prevState.monsters.length
)
)
};
This is the code I use to remove an item from array on position deleteItemPosition, because I can't use monsters.splice(deleteItemPosition, 1) because of immutability.
So why does my monsters array get cut off from deleteItemPosition to the end?
Try it yourself, entering some number 0-5 into "index to delete"
If I update line
let deleteItemPosition = this.state.deleteItemPosition;
and I hardcode it to, let say
let deleteItemPosition = 3;
Then I notice the item on position 3 gets removed, as I wanted.
Your deleteItem function could be simplified like this, also makes sure that no state updates are skipped:
deleteItem = () => {
this.setState(prevState => {
return { monsters: prevState.monsters.filter((_, i) => i !== +prevState.deleteItemPosition)};
})
};
The functional update is recommended as your new state(new monsters array) depends on the previous state.
Update:
You can use destructuring to avoid using prevState all the time. And you need to convert the deleteItemPosition to a number because the input's value is a string.
deleteItem = () => {
this.setState(({monsters, deleteItemPosition}) => {
return { monsters: monsters.filter((_, i) => i !== +deleteItemPosition)};
})
};
Just make a shallow copy of the monsters array, apply Array.prototype.splice method for deleting your item and return the copied monsters array.
const copyMonsters = [...prevState.monsters];
copyMonsters.splice(deleteItemPosition, 1);
return {
monsters: copyMonsters
}
Put this code inside the setState function in your case.

Deleting a particular element from an array

state = { filters: ['all'] }
this.state.filters.includes('humans') ?
this.state.filters.filter(val => val !== 'humans') : this.state.filters.push(dropdown)
I'm using a condition such that, when I click on a button the item('humans') gets pushed to state and when I click on the same button again I need to remove the item('humans') from the array. Push is working fine, I need help in removing it. I used filter like the above code , it does not get added again to the array but also not removing.
Thanks in advance.
Use:
let index = this.state.filters.indexOf('humans');
if (index !== -1)
this.state.filters.splice(index, 1);
Or you better follow this approach to avoid mutating the state in React:
let array = [...this.state.filters]; // make a separate copy of the array
let index = array.indexOf('humans')
if (index === -1) { // not in the array
array.push('humans');
this.setState({filters: array});
} else { // exists in the array
array.splice(index, 1);
this.setState({filters: array});
}
To remove an element from array, You can do below thing
filters.splice(index_of_the_val, 1);
You shouldn't modify the state with the push, 'cause it might not trigger the re-rendering. You should use the setState method.
toggleFilter = filter => {
const isIncluded = this.state.filters.includes(filter)
const add = (filters, filter) =>
filters.concat(filter)
const remove = (filters, filter) =>
filters.filter(f => f !== filter)
this.setState(prevState => ({
filters: isIncluded
? remove(prevState.filters, filter)
: add(prevState.filters, filter)
}))
}

Issue in removing object using Lodash _remove

I am having an Object:
ids = [ "-LIof_e0hPtXKtkc4Uh9", "-LIjBcGO7m7VQ-B3pfYt" ]
If I Iterate using .map function of lodash
_.map(ids, (userID, key) => {
console.log('Lopping userId',userID);
})
it gives me value of each id.
Now when I am trying to remove it using _remove it is not working as expected.
_.remove(ids, (value, key, obj) => value == idToBeRemoved);
Still there is no difference in ids Object.
I am really new to angular4 and using lodash for the first time.
I just wanted to remove a value from ids object and get the remaining object.
Print of console.
I am using firebase and trying to delete data after retrieving it from firebase :
deleteTransactWith(transactWithKey,transactWithUser) {
let currentUser = this._authService.getLoggedInUser();
console.log(transactWithUser.groups)
console.log(Object.keys(transactWithUser.groups).length)
console.log('key To remove',transactWithKey)
for (var key in transactWithUser.groups) {
if (transactWithUser.groups.hasOwnProperty(key)) {
let group = this.firebase.object(`/url/${currentUser.$key}/${key}`);
group.snapshotChanges().take(1).subscribe((groupData: any) => {
groupData = groupData.payload.toJSON();
//console.log('not removed',groupData.userIds)
console.log('key',transactWithKey)
_.remove(groupData.userIds, (value) => value == transactWithKey);
//_.pull(groupData.userIds, transactWithKey);
console.log('removed',groupData.userIds)
});
}
}
You want _filter instead
const ids = [ "-LIof_e0hPtXKtkc4Uh9", "-LIjBcGO7m7VQ-B3pfYt" ]
const idToBeRemoved = "-LIof_e0hPtXKtkc4Uh9"
const filteredIds = _.filter(ids, function(id) { return id !== idToBeRemoved})
console.log(filteredIds)
You can simply use lodash _.pull
const _ = require("lodash");
const ids = [ "-LIof_e0hPtXKtkc4Uh9", "-LIjBcGO7m7VQ-B3pfYt" ]
const result = _.pull(ids, "-LIjBcGO7m7VQ-B3pfYt" )
console.log(filteredIds)
First find the index of what you are removed item and next pull out from it by _.pullAt(lodash)
let getIndex= _.findIndex(this.images, function(o) { return o.name == img.name; });
let removedImage = _.pullAt(this.images, getIndex) ;

Loop in const object

I am trying to do the following:
const obj {
for(i=0;i<data.length;i++){
Key[i]: data[i].description
}
}
(I know I probably also needs to add a comma at the end of each line except on the last one, but I already get errors in the earlier stage)
This doesn't seem to be allowed in JS. Are there any alternatives? Thank you!
You could use Object.assign in combination with spread syntax ... and map the single objects with Array#map and use computed property names for the object.
const obj = Object.assign(...data.map((o, i) => ({ ['Key' + i]: o.description })));
It looks like you're trying to create an object from a keys array and a data array.
A clean approach would be to use array reduction:
const obj = data.reduce((obj, d, i) => {
obj[Key[i]] = d.description;
return obj;
}, {});
which, assuming your environment allows it, can be simplified further (due note that this will be cleaner code but less efficient because the object spread copies the entire object every time):
const obj = data.reduce((obj, d, i) => ({
...obj,
[Key[i]]: d.description
}), {});
but you could also use a simple for loop:
const obj = {};
for (let i = 0; i < data.length; i++) {
obj[Key[i]] = data[i].description;
}
Note: The code above will break if Key.length !== data.length.

Categories

Resources