Reputation: 742
I would like to remove an item from array onClick by using the prevState syntax.
Here is an example code that i use:
export default function App() {
const [selected, setSelected] = useState(false);
const [selectedItems, setSelectedItems] = useState([]);
const [cards, setCards] = useState(["card1", "card2", "card3", "card4"]);
function handleButtonClick(event) {
setSelected(true);
let key = event.target.id;
key = parseInt(key, 10);
if (selectedItems.indexOf(key) === -1) {
setSelectedItems([...selectedItems, key]);
} else {
// HOW do i remove the item from the array ????
let index = selectedItems.indexOf(key);
}
}
return (
<div className="App">
{cards.map((card, index) => (
<button
className={
selected && selectedItems.indexOf(index) !== -1
? "button1 active"
: "button1"
}
onClick={handleButtonClick}
id={index}
>
{card}
</button>
))}
</div>
);
}
link to sandbox as well : https://codesandbox.io/s/patient-thunder-mb1vx?file=/src/App.js
Upvotes: 1
Views: 156
Reputation: 1074385
I find it odd that the simple, standard answer hasn't been posted:
function handleButtonClick(event) {
setSelected(true);
const key = parseInt(event.target.id, 10);
setSelectedItems(selectedItems => {
const itemIndex = selectedItems.indexOf(key);
if (itemIndex === -1) {
// New item, add it
selectedItems = [...selectedItems, key];
} else {
// New item, add it
selectedItems = selectedItems.filter((_, index) => index !== itemIndex); // ***
}
return selectedItems;
});
}
Notice that since this sets state based on existing state, it's best to use the callback form of the state setter.
Upvotes: 0
Reputation: 169032
An option using Array#splice
that uses the function form of setState
:
const [items, setItems] = React.useState([]);
const deleteItemAtIndex = (index) => setItems(items => {
const newItems = [...items];
newItems.splice(index, 1);
return newItems;
});
This has the advantage that it can be memoized (useCallback
) without needing items
as a dependency (since setItems
is always stable and the function itself doesn't use items
, only the callback does):
const deleteItemAtIndex = React.useCallback((index) => setItems(items => {
const newItems = [...items];
newItems.splice(index, 1);
return newItems;
}), []);
Upvotes: 1
Reputation: 834
An alternative to @CertainPerformance using splice
:
const copy = [...selectedItems];
const index = copy.indexOf(key);
copy.splice(index, 1);
setSelectedItems(copy);
Upvotes: 1
Reputation: 1361
You can make a copy of your array, splice the index from the copy then set the state with the new array.
const newArray = [...oldArray]
newArray.splice(index, 1)
setSelectedItems(newArray)
Upvotes: 1
Reputation: 622
Use this one. Hope it will work.
if (selectedItems.indexOf(key) === -1) {
setSelectedItems([...selectedItems, key]);
} else {
// HOW do i remove the item from the array ????
let index = selectedItems.indexOf(key);
const arr = selectedItems.filter((item, i) => i !== index);
setSelectedItems(arr);
}
Check this link https://codesandbox.io/s/stupefied-greider-m25le
Upvotes: 1
Reputation: 370779
Once you've found the index of the key in selectedItems
, set selectedItems
's state by slicing the array before and after that index:
const index = selectedItems.indexOf(key);
setSelectedItems([
...selectedItems.slice(0, index),
...selectedItems.slice(index + 1)
]);
const { useState } = React;
const App = () => {
const [selected, setSelected] = useState(false);
const [selectedItems, setSelectedItems] = useState([]);
const [cards, setCards] = useState(["card1", "card2", "card3", "card4"]);
function handleButtonClick(event) {
setSelected(true);
let key = event.target.id;
key = parseInt(key, 10);
if (selectedItems.indexOf(key) === -1) {
let index = selectedItems.indexOf(key);
setSelectedItems([...selectedItems, key]);
} else {
const index = selectedItems.indexOf(key);
setSelectedItems([
...selectedItems.slice(0, index),
...selectedItems.slice(index + 1)
]);
}
}
return (
<div className="App">
{cards.map((card, index) => (
<button
className={
selected && selectedItems.indexOf(index) !== -1
? "button1 active"
: "button1"
}
onClick={handleButtonClick}
id={index}
key={index}
>
{card}
</button>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
.App {
font-family: sans-serif;
text-align: center;
}
.active {
border: 2px solid green;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class="react"></div>
Also remember to use a unique key
prop for lists, and to prefer const
over let
whenever possible.
Upvotes: 1