I have an event handler that is meant to filter a chosen item out of a stateful array. Currently it is filtering everything out of the array instead of the intended selection.
So when I click the remove button of one card both/all cards are removed even though they have different ids...
Lastly, how can I filter the menu cards based on the searchbar
input?
This is what my components looks like
top level
import Favorites from "./Favorites";
import { Menu } from "./Menu";
import { useState } from "react";
import "./App.css";
function App() {
const [favorite, setFavorite] = useState([]);
const [array, setArray] = useState([
{
text: "Check 123",
name: "Lahmacun",
image: "src/lahmacun.jpeg",
id: self.crypto.randomUUID(),
liked: false,
},
{
text: "Check 456",
name: "Chicken",
image: "src/chicken.webp",
id: self.crypto.randomUUID(),
liked: false,
},
{
text: "Check 789",
name: "Veggies",
image: "src/vegan.jpeg",
id: self.crypto.randomUUID(),
liked: false,
},
{
text: "Check 012",
name: "Pho",
image: "src/pho.jpeg",
id: self.crypto.randomUUID(),
liked: false,
},
]);
const handleLike = (card) => {
setFavorite((prev) => [...prev, card]);
};
const handleUnlike = (id) => {
console.log("removed");
setFavorite(favorite.filter((item) => item.id == id));
};
return (
<div id="app">
<h1>Recipes To Try</h1>
<form className="m-2" action="">
<div className="row">
<div className="col-3 ">
<label className="form-label pt-2" id="searchBar">
Find A Recipe
</label>
</div>
<div className="col-md-7 col-5">
<input
//onChange={filterRecipes}
type="text"
className="form-control"
id="searchBar"
placeholder="Search"
/>
</div>
<div className="col-sm-1 col-2">
<button type="submit" className="btn btn-primary" id="searchBtn">
Search
</button>
</div>
</div>
</form>
<Favorites favorite={favorite} handleUnlike={handleUnlike} />
<Menu array={array} handleLike={handleLike} />
</div>
);
}
export default App;
favorite component
export default function Favorites({ favorite, handleUnlike }) {
return (
<>
<div className="holder">
<h3>Favorites</h3>
<div id="favorites">
{favorite.map((i) => (
<div
className="col col-md mb-3 mb-sm-0"
key={self.crypto.randomUUID()}
>
<div className="card">
<img src={i.image} alt="" className="card-img-top " />
<div className="card-body">
<h5 className="card-title">{i.name}</h5>
<p className="card-text">{i.text}</p>
<a
onClick={() => handleUnlike(i)}
href="#"
className="btn btn-primary"
>
Remove
</a>
</div>
</div>
</div>
))}
</div>
</div>
</>
);
}
Menu component
import { Cards } from "./Cards";
export function Menu({ array, handleLike }) {
return (
<div id="menu">
<div className="row">
<div className="col">
<h3 className="">Ready for Testing</h3>
</div>
</div>
<div className="row">
<Cards array={array} handleLike={handleLike} />
</div>
</div>
);
}
Card Component
export function Cards({ array, handleLike }) {
return (
<>
{array.map((i) => (
<div className="col col-md mb-3 mb-sm-0" key={i.id}>
<div className="card">
<img src={i.image} alt="" className="card-img-top " />
<div className="card-body">
<h5 className="card-title">{i.name}</h5>
<p className="card-text">{i.text}</p>
<a
onClick={() => handleLike(i)}
href="#"
className="btn btn-primary"
>
Add to Favorites
</a>
</div>
</div>
</div>
))}
</>
);
}
Thanks a bunch 💪
I expect just one item to be filtered but both were
problem is your i passed in handleUnlike is not the id but the object.
<a onClick={() => handleUnlike(i)}
href="#"
className="btn btn-primary"
>
change it to this and it will work
<a onClick={() => handleUnlike(i.id)}
href="#"
className="btn btn-primary"
>
the origin of your problem is inproper naming of your objects if you give everything a meaningful name, you will spot these errors easier.
instead of
{favorite.map((i) => (...))}
do
{favoriteRecipes.map((recipe) => (...))}
for filtering, instead of showing the original list, you create a second list.
because you are using a button for searching you will need to add a useRef for the textfield. (this will prevent unnecessary rerendering)
const [filteredRecipes, setFilteredRecipes] = useState(array);
const searchTextRef = useRef();
then in the onClick handler of the searchButton, you do the filtering.
const onSearchRecipe = () => setFilteredRecipes(array.filter(recipe => recipe.name.includes(searchTextRef.current.value) !== -1));
change the part of your inputfield and button to the following
<div className="col-md-7 col-5">
<input
type="text"
ref={searchTextRef}
className="form-control"
id="searchBar"
placeholder="Search"
/>
</div>
<div className="col-sm-1 col-2">
<button
onClick={onSearchRecipe} type="button" className="btn btn-primary" id="searchBtn">
Search
</button>
</div>
and then last pass in your filtered list to the menu instead of the array
<Menu array={filteredRecipes} handleLike={handleLike} />