I need to update an array in the state of my component in React.
I've seens several topic with this question, but so far all of them are adding new items to the array with the spread operator, but I need to add OR remove items on a callback like this:
handleCheck (newStatus, isChecked) {
this.setState({ filterStatus: [...this.state.filterStatus, newStatus] })
}
But the problem here is that it didn't work for status where the isChecked boolean comes false to remove them from the array
What is the best way to add or remove items from that array, hopefully with spread operator?
Thanks
try to use the .filter to remove the element. Remember to duplicate the array (using [...array] syntax) before using .filter, to don't change the original array:
handleCheck (newStatus, isChecked) {
let newArray = isChecked? // if isChecked is true
[...this.state.filterStatus, newStatus] : // add element
[...this.state.filterStatus].filter(e => e !== newStatus); // remove the elements that are equal to newStatus
this.setState({ filterStatus: newArray})
}
Think it functionnal !
const prevArray = this.state.array;
const itemsToAdd = [item, item, item];
//this function map the prev array escaping elements to remove
//and then push itemsToAdd to the new array
const updateArray = ( i = [0], newArray = [] ) =>
i < prevArray ?
yourRemovingCondition(prevArray[i]) ?
updateArray( i + 1, newArray )
: updateArray( i + 1, [...newArray, prevArray[i])
: [...newArray, ...itemsToAdd]
;
setState({array: updateArray()];
Put the check, add the element only when the bool isChecked is true, otherwise use filter to remove the element from the array.
Like this:
handleCheck (newStatus, isChecked) {
this.setState(prevState => {
let filterStatus;
if (isChecked) {
filterStatus = [...prevState.filterStatus, newStatus];
} else {
filterStatus = prevState.filterStatus.filter(el => el.id !== newStatus.id)
}
return { filterStatus }
})
}
Note: In place of id in filter callback method use the correct unique property name.
Related
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.
I want to remove a specific element from an array, I am getting the key of the element from the input.
I want to be able to remove the element only by knowing the key.
This is the array:
state ={
splitAmount : [{
"SplitAmount0": this.props.data.amount1
}, {
"SplitAmount1": this.props.data.amount2
}, {
"SplitAmount2": this.props.data.amount3
}]
}
Remove function:
removeSplitAmount(e) {
console.log("remove",e.target.name)
let array = [...this.state.splitAmount];
let index = this.state.splitAmount.IndexOf(p => p == e.target.name )
if (index !== -1) {
array.splice(index, 1);
this.setState({splitAmount: array});
}
}
You can use the .filter method on the array combined with the Object.keys to clean the function up a lot:
removeSplitAmount(e) {
const newSplitAmount = this.state.splitAmount
.filter(p => !Object.keys(p).includes(e.target.name));
this.setState({ splitAmount: newSplitAmount });
}
You can use hasOwnProperty to filter objects you need.
removeSplitAmount(e) {
const newSplitAmount = this.state.splitAmount
.filter(x => !x.hasOwnProperty(e.target.name));
this.setState({ splitAmount: newSplitAmount });
}
As Dmitry said you can't do a indexOf on an array of objects... i felt bad i didn't realize that.
Would be useful on this case:
var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
beasts.indexOf('bison')
On your case you are better to go with the .filter method as said in above answers because you are searching for and object with a specific property
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)
}))
}
I am working in a ReactJS project and have a filterGroupsData property in my state. This is an array of objects, each object has a filters property which is an array of string values. See below:
filterGroupsData:[
{"key":1532957059388,"id":1532957059388,"filters":[]},
{"key":1532957059612,"id":1532957059612,"filters":[]},
{"key":1532957059847,"id":1532957059847,"filters":[]}
]
How can I add elements to the filters property of a object with a given id?
I attempted to this but this results in overwriting the whole object with on value:
// update the filter array of the object with id == activeId
let updatedFilterGroupsData = filterGroupsData.map(filterGroupData => filterGroupData.id === activeId ? filterGroupData.filters.push('test') : filterGroupData)
this.setState({filterGroupsData: updatedFilterGroupsData});
Appreciate any help.
You can use findIndex to get the index of the filter group you want to update, and then create a copy of the object and the filters array and add a new entry to it.
Example
const id = 1532957059388;
this.setState(previousState => {
const filterGroupsData = [...previousState.filterGroupsData];
const index = filterGroupsData.findIndex(group => group.id === id);
filterGroupsData[index] = {
...filterGroupsData[index],
filters: [...filterGroupsData[index].filters, "new filter"]
};
return { filterGroupsData };
});
Here: filterGroupData.filters = 'test'
You're setting the prop value to a string instead of putting in the array.
You need to push the item into the filters array like:
filterGroupData.filters.push('test');
filters is a array so you need to use push('test') with multi line code inside map:
var filterGroupsData = [
{"key":1532957059388,"id":1532957059388,"filters":[]},
{"key":1532957059612,"id":1532957059612,"filters":[]},
{"key":1532957059847,"id":1532957059847,"filters":[]}
]
var activeId = 1532957059612;
let updatedFilterGroupsData = filterGroupsData.map((filterGroupData) => {
if(filterGroupData.id === activeId) {
filterGroupData.filters.push('test');
}
return filterGroupData
});
console.log(updatedFilterGroupsData);
I can't figure out how to complete this function. I have filtered through to find the variable that matches the id but now I need to match that item to the delItem var and delete it.
function deleteToDo(tot) {
let delItem = toDos.filter((remove) => remove.id === tot);
/// i need to remove item from toDos array that matches delItem.
renderTheUI(toDos);
}
Array#filter returns an array, with all items that match the predicate. Instead of getting the item that you want to remove, get an array without the item by checking that the id is not equal to tot. Then use the filtered array in renderTheUI:
function deleteToDo(tot) {
const filteredToDos = toDos.filter((item) => item.id !== tot);
renderTheUI(filteredToDos);
}
I would suggest moving the call to renderTheUI out of the deleteToDo method, since it might be very confusing. The deleteToDo will return an updated array, and then you can render the new array:
function deleteToDo(tot) {
return toDos.filter((item) => item.id !== tot);
}
const filteredToDos = deleteToDo(2);
renderTheUI(filteredToDos);
You do not need to find the element with filter but its index in the array.
function deleteToDo(tot) {
let delIndex = toDos.findIndex((remove) => remove.id === tot);
if (delIndex !== -1){ // if element was found
toDos.splice(delIndex,1); // remove the element from the toDos array
}
renderTheUI(toDos);
}