Reputation: 81
I'm working on a Tinder-like app and trying to remove the current card from the array and move on to the next when clicking either the like or dislike button. Simultaneously, I am trying to add the card to a new array (list of liked or disliked). Adding the object to new array seems to work (although there's a delay and the button needs clicked twice - which also needs to be sorted), but as soon as I try to remove it from the current array it all crashes.
I tried looking at this solution: Removing object from array using hooks (useState) but I only ever get "TypeError: Cannot read property 'target' of undefined" no matter what I try. What am I missing?
This is the code:
import React, { useState, useEffect } from 'react';
import { Card, Button, Container } from 'react-bootstrap';
const url = 'https://swiperish-app.com/cards';
const SwiperCard = () => {
const [cardData, setCardData] = useState([]);
const [likedItem, setLikedItem] = useState([]);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(cardData => setCardData(cardData))
});
const handleRemoveItem = (event) => {
const name = event.target.getAttribute("name")
setCardData(cardData.filter(item => item.id !==name));
};
const likedCards = (itemId, itemImg, ItemTitle) => {
let likedArr = [...likedItem];
setLikedItem(likedItem => likedItem.concat({itemId, itemImg, ItemTitle}))
handleRemoveItem();
console.log(likedArr);
};
return (
<div id="contentView">
{cardData.map((item, index) => {
return(
<Card key={index} className="cardContainer" name={item.id}>
<Container className="btnContainer">
<div className="btnWrapper">
<Button className="btn" onClick={() => console.log(item.id)}>DISLIKE</Button>
</div>
</Container>
<Container className="cardContentContainer">
<Card.Img style={{width: "18rem"}}
variant="top"
src={item.image}
fluid="true"
/>
<Card.Body style={{width: "18rem"}}>
<Card.Title className="cardTitle">{item.title.toUpperCase()}</Card.Title>
<Card.Subtitle className="cardText">{item.body}</Card.Subtitle>
</Card.Body>
</Container>
<Container className="btnContainer">
<div className="btnWrapper">
<Button className="btn" onClick={() => likedCards(item.id, item.image,item.title) }>LIKE</Button>
</div>
</Container>
</Card>
)
})}
</div>
);
};
export default SwiperCard;
Upvotes: 0
Views: 741
Reputation: 78890
You're calling handleRemoveItem
with no arguments, but that function is doing something with an event
parameter, so you're going to get a TypeError.
It seems like handleRemoveItem
really only needs to know about the item ID to remove, so you can simplify to:
const removeCard = id => {
setCardData(cardData.filter(item => item.id !== id));
};
const handleLike = (itemId, itemImg, ItemTitle) => {
setLikedItem([...likedItem, {itemId, itemImg, ItemTitle}]);
removeCard(itemId);
};
I also noticed that you're sometimes logging a state variable immediately after calling the setting. That won't work. It's not until the next call to useState
on the next render when you'll receive the value, so if you want to log changes to state, I'd log in your render function, not in an event handler.
Upvotes: 0
Reputation: 342
You can move cards between two arrays with
const likedCards = (item) => {
setLikedItem([...likedItem, item]);
let filtered = cardData.filter((card) => card.itemId !== item.itemId);
setCardData(filtered);
};
I suggest you to add empty array as second parameter of useEffect,since you are using as componentDidMount.
As second suggestion you can setLoading true before fetch and setLoading false after to reduce errors in render.
Upvotes: 1