React 事件处理程序未从对象数组中删除对象(useState)

问题描述 投票:0回答:1

我正在尝试制作一个播放列表应用程序,您可以在其中使用搜索结果创建您自己的播放列表。我已经成功地将搜索结果中的歌曲传递到播放列表,但是当我尝试删除它们时,我无法删除整个卡。相反,只有艺术家、歌曲和专辑消失,但卡片仍保留在列表中。

enter image description here

enter image description here

正如您所看到的,在我单击删除按钮后,卡片仍然存在,但其文本消失了。

这就是我的文件的样子

顶级应用程序组件

import { useState, useCallback } from "react";
import SearchBar from "./SearchBar";
import SearchResults from "./SearchResults";
import Playlist from "./Playlist";
import styles from "../Styles/App.module.css";

const generateKey = () => {
  let num = "";
  let characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  const chars = characters.length;

  for (let i = 0; i < 5; i++) {
    num += characters.charAt(Math.floor(Math.random() * chars));
  }

  return num;
};

function App() {
  const [playlistTracks, setPlaylistTracks] = useState([]);
  const [searchResults, setSearchResults] = useState([
    {
      song: "Go Baby",
      artist: "Lupe",
      album: "Food and Liqour",
      id: generateKey(),
    },
    {
      song: "Demon Days",
      artist: "Gorillaz",
      album: "Self titled",
      id: generateKey(),
    },
  ]);

  const onAdd = (track) => {
    setPlaylistTracks((prevTracks) => [...prevTracks, track]);
  };

  const onRemove = (e) => {
    console.log(playlistTracks);
    setPlaylistTracks([playlistTracks.filter((song) => song.id == e.id)]);
  };

  return (
    <div id={styles.app}>
      <header>
        <h1>Spotify Playlist App</h1>
      </header>
      <SearchBar />
      <main>
        <SearchResults searchResults={searchResults} onAdd={onAdd} />
        <Playlist
          playlistTracks={playlistTracks}
          name="playlist"
          onRemove={onRemove}
        />
      </main>
    </div>
  );
}

export default App;

这是我的播放列表组件

import React, { useState } from "react";
import styles from "../Styles/Playlist.module.css";
import Tracklist from "./Tracklist";

function Playlist(props) {
  const { playlistTracks } = props;
  const [name, setName] = useState("Playlist");

  const nameList = (e) => {
    e.preventDefault();
    setName(e.target.value);
  };

  return (
    <div id={styles.playlist}>
      <h3>{name}</h3>
      <input onChange={nameList} type="text" />
      <Tracklist
        tracks={playlistTracks}
        string="playlist"
        onRemove={props.onRemove}
      />
      <button>Save to Spotify</button>
    </div>
  );
}

export default Playlist;

曲目列表组件

import React from "react";
import Track from "./Track";

function Tracklist(props) {
  const generateKey = () => {
    let num = "";
    let characters =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    const chars = characters.length;

    for (let i = 0; i < 5; i++) {
      num += characters.charAt(Math.floor(Math.random() * chars));
    }

    return num;
  };

  return (
    <div>
      {props.tracks.map((track) => {
        return (
          <Track
            key={generateKey()}
            track={track}
            onAdd={props.onAdd}
            onRemove={props.onRemove}
            string={props.string}
          />
        );
      })}
    </div>
  );
}

export default Tracklist;

轨道组件

import React, { useCallback } from "react";
import styles from "../Styles/Track.module.css";

function Track(props) {
  const string = props.string;

  const choice = () => {
    switch (string) {
      case "search": {
        return <button onClick={() => props.onAdd(props.track)}>+</button>;
      }
      case "playlist": {
        return <button onClick={() => props.onRemove(props.track)}>-</button>;
      }
      default: {
        return undefined;
      }
    }
  };

  return (
    <div id={styles.track}>
      <div id={styles.track_info}>
        <h4>{props.track.song}</h4>
        <p>
          {props.track.artist} | {props.track.album}
        </p>
      </div>
      {choice()}
    </div>
  );
}

export default Track;

我尝试从搜索结果中删除添加的卡片,但无济于事

reactjs react-hooks onclick react-props
1个回答
0
投票

您的

onRemove()
函数可能编码不正确。

setPlaylistTracks([playlistTracks.filter((song) => song.id == e.id)]);

这将在每次调用时创建一个数组的数组。

playlistTracks.filter()
的结果将是一个数组,然后创建一个具有
playlistTracks.filter()
结果的单成员数组,即一个数组的数组。相反,请考虑删除外部数组构造函数:

setPlaylistTracks(playlistTracks.filter((song) => song.id == e.id));

此外,由于该函数被命名为

onRemove
,看起来您可能正在从状态中删除通过的轨迹。目前,这将排除除通过的轨道之外的所有其他轨道。考虑将
filter()
回调中的逻辑反转为(严格)不等于 (
!==
):

setPlaylistTracks(playlistTracks.filter((song) => song.id !== e.id));

最后,为了防止任何可能的过时状态,请考虑将函数传递给

setPlaylistTracks
。该函数将接收最新状态并返回新状态:

setPlaylistTracks((tracks) => tracks.filter((song) => song.id !== e.id));

const { useState, useCallback } = React;

function Playlist(props) {
  const { playlistTracks } = props;
  const [name, setName] = useState("Playlist");

  const nameList = (e) => {
    e.preventDefault();
    setName(e.target.value);
  };

  return (
    <div id={styles.playlist}>
      <h3>{name}</h3>
      <input onChange={nameList} type="text" />
      <Tracklist
        tracks={playlistTracks}
        string="playlist"
        onRemove={props.onRemove}
      />
      <button>Save to Spotify</button>
    </div>
  );
}

function Tracklist(props) {
  const generateKey = () => {
    let num = "";
    let characters =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    const chars = characters.length;

    for (let i = 0; i < 5; i++) {
      num += characters.charAt(Math.floor(Math.random() * chars));
    }

    return num;
  };

  return (
    <div>
      {props.tracks.map((track) => {
        return (
          <Track
            key={generateKey()}
            track={track}
            onAdd={props.onAdd}
            onRemove={props.onRemove}
            string={props.string}
          />
        );
      })}
    </div>
  );
}

const styles = {
  track: 'track',
  track_info: 'track_info',
};

function Track(props) {
  const string = props.string;

  const choice = () => {
    switch (string) {
      case "search": {
        return <button onClick={() => props.onAdd(props.track)}>+</button>;
      }
      case "playlist": {
        return <button onClick={() => props.onRemove(props.track)}>-</button>;
      }
      default: {
        return undefined;
      }
    }
  };

  return (
    <div id={styles.track}>
      <div id={styles.track_info}>
        <h4>{props.track.song}</h4>
        <p>
          {props.track.artist} | {props.track.album}
        </p>
      </div>
      {choice()}
    </div>
  );
}

const generateKey = () => {
  let num = "";
  let characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  const chars = characters.length;

  for (let i = 0; i < 5; i++) {
    num += characters.charAt(Math.floor(Math.random() * chars));
  }

  return num;
};

const SearchBar = () => 'SearchBar';
const SearchResults = ({ searchResults, onAdd }) => (
  <React.Fragment>
    {searchResults.map(result => (
      <button onClick={() => onAdd(result)}>
        {result.song}
      </button>
    ))}
  </React.Fragment>
);

function App() {
  const [playlistTracks, setPlaylistTracks] = useState([]);
  const [searchResults, setSearchResults] = useState([
    {
      song: "Go Baby",
      artist: "Lupe",
      album: "Food and Liqour",
      id: generateKey(),
    },
    {
      song: "Demon Days",
      artist: "Gorillaz",
      album: "Self titled",
      id: generateKey(),
    },
  ]);

  const onAdd = (track) => {
    setPlaylistTracks((prevTracks) => [...prevTracks, track]);
  };

  const onRemove = (e) => {
    console.log(playlistTracks);
    setPlaylistTracks(tracks => tracks.filter((song) => song.id !== e.id));
  };

  return (
    <div id={styles.app}>
      <header>
        <h1>Spotify Playlist App</h1>
      </header>
      <SearchBar />
      <main>
        <SearchResults searchResults={searchResults} onAdd={onAdd} />
        <Playlist
          playlistTracks={playlistTracks}
          name="playlist"
          onRemove={onRemove}
        />
      </main>
    </div>
  );
}


ReactDOM.createRoot(document.getElementById('app')).render(<App/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js" integrity="sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js" integrity="sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<div id="app"></div>

© www.soinside.com 2019 - 2024. All rights reserved.