Удаление объекта из одного массива с одновременным добавлением его в другой массив - React hooks

Я работаю над приложением, похожим на Tinder, и пытаюсь удалить текущую карту из массива и перейти к следующей, нажимая кнопку «Нравится» или «Не нравится». Параллельно пытаюсь добавить карту в новый массив (список понравившихся или не понравившихся). Кажется, что добавление объекта в новый массив работает (хотя есть задержка, и кнопку нужно дважды щелкнуть, что также необходимо отсортировать), но как только я пытаюсь удалить его из текущего массива, все происходит сбой.

Я попытался найти это решение: Удаление объекта из массива с помощью хуков (useState), но я получаю только TypeError: не могу прочитать свойство 'target' из undefined, что бы я ни пытался. Что мне не хватает?

Это код:

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;

person BBHeX    schedule 17.08.2020    source источник


Ответы (2)


Вы вызываете handleRemoveItem без аргументов, но эта функция что-то делает с параметром event, поэтому вы получите TypeError.

Похоже, что handleRemoveItem действительно нужно знать только об идентификаторе элемента, который нужно удалить, поэтому вы можете упростить:

const removeCard = id => {
  setCardData(cardData.filter(item => item.id !== id));
};

const handleLike = (itemId, itemImg, ItemTitle) => {
  setLikedItem([...likedItem, {itemId, itemImg, ItemTitle}]);
  removeCard(itemId);
};

Я также заметил, что иногда вы регистрируете переменную состояния сразу после вызова настройки. Это не сработает. Вы получите значение только при следующем вызове useState при следующем рендеринге, поэтому, если вы хотите регистрировать изменения состояния, я бы зарегистрировал вашу функцию рендеринга, а не в обработчике событий.

person Jacob    schedule 18.08.2020

Вы можете перемещать карты между двумя массивами с помощью

 const likedCards = (item) => {
    setLikedItem([...likedItem, item]);
    let filtered = cardData.filter((card) => card.itemId !== item.itemId);
    setCardData(filtered);
  };

Я предлагаю вам добавить пустой массив в качестве второго параметра useEffect, поскольку вы используете как componentDidMount.

В качестве второго предложения вы можете установить Loading true перед выборкой и setLoading false после, чтобы уменьшить количество ошибок при рендеринге.

person Ubeyt Demir    schedule 17.08.2020
comment
Извините, я все еще немного заблудился ... неужели вы не можете назначить новое значение cardData таким образом, поскольку это константа? - person BBHeX; 18.08.2020
comment
Извините за путаницу :) Я обновил решение, не забудьте передать весь объект элемента в функцию - person Ubeyt Demir; 18.08.2020
comment
Теперь все карточки пропадали сразу, а не по одной, а в журнале консоли ничего не значилось. Извините, но, очевидно, мне очень нужно, чтобы мне это объяснили, как будто мне 5 лет. - person BBHeX; 18.08.2020
comment
@BBHeX Надеюсь, это сработает для вас, я также добавил кнопку возврата codeandbox.io/s/ - person Ubeyt Demir; 18.08.2020