BBHeX
BBHeX

Reputation: 81

Removing object from one array while simultaneously adding it to a different array - React hooks

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

Answers (2)

Jacob
Jacob

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

Ubeyt Demir
Ubeyt Demir

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

Related Questions