从零开始用 React 构建音乐播放器应用程序🔥🎶
在本博客教程中,我们将从头开始使用 react.js 设置和构建音乐播放器应用程序。
如果您想了解有关 React 的更多信息,这里有一篇专门为您准备的文章。
我们将从零开始构建 UI 及其功能。不过,在开始之前,应用程序的最终版本应该是这样的。
您还可以查看此应用程序的最终实时版本。
那么,事不宜迟,让我们开始这个派对吧。
安装 React 应用程序
让我们开始我们的第一个 React 应用程序。如果你的系统上还没有安装 Node.js,那么首先需要安装它。访问 Node.js 官方网站并安装正确且合适的版本。我们需要 Node.js 是因为我们可以利用 Node 包管理器或 NPM 功能。
现在,创建一个空白文件夹,并在您选择的代码编辑器中打开它。在本教程中,我将使用 VScode。下一步,让我们打开集成终端并输入 npx create-react-app music-payer-react-app 。此命令将在当前目录中创建应用程序,该应用程序将命名为 music-payer-react-app。
安装通常只需几分钟。通常,下载软件包时,我们会使用 npm 将它们下载到项目中,但这里我们使用 npx,即软件包运行器,它会帮我们下载并配置所有内容,以便我们能够使用一个很棒的模板开始开发。现在,是时候启动我们的开发服务器了,只需输入 npm start,它就会自动在浏览器中打开 react-app。
样板模板的初始显示效果如下。现在,我们来研究一下 create-react-app 提供的文件和文件夹结构。其中有一个名为 node module 的文件夹,其中包含我们所有的 node 依赖项。然后是 public 文件夹,其中唯一重要的就是 index.html 文件。因此,这看起来像是一个标准的 HTML 文件,包含 head、body 和 meta 标签。您会注意到 body 标签内有一个 id 为 root 的 div,后面跟着 fallback noscript 标签,该标签只有在用户浏览器禁用 JavaScript 时才会显示。
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React practice</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
所以你可能想知道内容从哪里来。记住,我们所有的源代码都包含在 source 或 src 文件夹中,React 会将其注入到根 div 元素中。让我们看一下 src 文件夹,其中包含一些样式表、JavaScript 文件和 SVG 文件。
现在,转到我们的 App.js 文件
// App.js
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
在本例中,我们只是使用标准 JavaScript 从 react 导入 react,从 logo 导入 logo。接下来,我们有一个名为 APP 的普通 JavaScript 函数,这个函数在 React 中被称为函数组件,它返回一个看起来像 HTML 但实际上是 jsx 的 react 元素,如您所见,有一个 div 标签,其 className 为 APP,我们不能单独说 class,因为 class 是 JavaScript 中的保留字,所以在 jsx 中我们必须使用 className。接下来,我们有标题和图像,请注意,在图像源上有我们的徽标,它实际上是我们在顶部导入的一个 JavaScript 变量,因此为了在 JSX 中使用 JavaScript,我们必须用花括号将其括起来,然后我们有一个段落、一个锚标记,这就是这个组件的全部内容。
注意:由于导出功能,我们可以提取组件并将其放置在网页上。export 出现在 app.js 文件的底部,表示我们正在导出 App 函数。
那么,现在让我们看一下 index.js 文件。
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
所以,在这种情况下,我们再次从 react 导入 react,这次我们还导入了 react-dom,然后导入 CSS 样式表文件,最后,我们从 App.js 导入 App(这是我们刚刚讨论过的文件),还有 service worker,它用于让你的应用程序完全离线工作。然后我们调用 ReactDom.render,它接受两个参数。第一个参数是 jsx 对象,在 jsx 中我们可以包含用户定义的组件,因此 react strict mode 是一个 react 定义的组件,而 App 是一个用户定义的组件,第二个参数是 document.getElementById('root'),它指向 index.html 文件中的根 div,也是我们访问网页内容的方式。
注意:ReactDom 将我们的内容呈现到位于 index.html 文件的根 div 中。
创建音乐播放器应用程序。
让我们从头开始在 React 中创建一个简单的音乐播放器应用程序,但首先,让我们创建最终应用程序的原型或思维导图。
所以,我们的最终应用程序看起来会像这样。
在开始构建项目之前,我们必须先清理一下 create-react-app 提供的一些文件。清理完成后,你的 src 文件应该如下所示。
现在,在公共文件夹中,创建另一个名为 songs 和 songs_images 的文件夹,并在该 songs 文件夹中添加所有您想要的歌曲,并在 songs_images 中添加该歌曲的封面图片。
所有歌曲和歌曲图片均可从此处下载
React-music-player-app(Github)
现在,转到你的 App.js 文件并创建一个 useState() 钩子,因为这个钩子将使我们能够将状态集成到我们的函数组件中。与类组件中的状态不同,useState() 不适用于对象值。如有必要,我们可以直接使用原语,并为多个变量创建多个 React 钩子。
const [state,setState] = useState(initialState);
React 中的 Hook 必须始终在函数顶部声明。这也有助于在组件的所有渲染之间保存状态。现在,将 songs 的初始化代码修改如下图所示:
将以下代码复制并粘贴到您的 App.js 文件中。
// App.js
import React from 'react';
import {useState,useEffect} from "react";
import './App.css';
const App=()=> {
const [songs,setSongs] = useState([
{
"title": "$orries",
"artist": "Peachy!",
"album": " Shiloh",
"track": "$orries",
"year": "1",
"img_src": "./songs_images/$orries_Cover (front)_e.jpg",
"src": "./songs/$orries.mp3"
},
{
"title": "[oops]",
"artist": "potsu",
"album": "[oops]",
"track": "1",
"year": "",
"img_src": "./songs_images/[oops]_Cover (front)_e.jpg",
"src": "./songs/[oops].mp3"
},
{
"title": "5:32pm",
"artist": "The Deli",
"album": "Vibes 2",
"track": "12",
"year": "",
"img_src": "./songs_images/5 32pm_Cover (front)_e.jpg",
"src": "./songs/5 32pm.mp3"
},
{
"title": "88 Keys",
"artist": "Oatmello",
"album": "Snapshots",
"track": "3",
"year": "",
"img_src": "./songs_images/88 Keys_Cover (front)_e.jpg",
"src": "./songs/88 Keys.mp3"
},
{
"title": "Affection",
"artist": "Jinsang",
"album": "Life",
"track": "15",
"year": "",
"img_src": "./songs_images/Affection_Cover (front)_e.jpg ",
"src": "./songs/Affection.mp3"
},
{
"title": "Again",
"artist": "Wun Two",
"album": "Penthouse",
"track": "4",
"year": "",
"img_src": "./songs_images/Again_Cover (front)_e.jpg",
"src": "./songs/Again.mp3"
},
{
"title": "Alone and Lonely",
"artist": "prxz",
"album": " Shiloh Dynasty",
"track": "Love Wounds",
"year": "2",
"img_src": "./songs_images/Alone and Lonely_Cover (front)_e.jpg",
"src": "./songs/Alone and Lonely.mp3"
},
{
"title": "Baby You're Worth It",
"artist": "Kina",
"album": "Baby You're Worth It",
"track": "1",
"year": "",
"img_src": "./songs_images/Baby You're Worth It_Cover (front)_e.jpg",
"src": "./songs/Baby You're Worth It.mp3"
},
{
"title": "Backpack City",
"artist": "Flovry",
"album": " tender spring",
"track": "Ages Ago",
"year": "4",
"img_src": "./songs_images/ ",
"src": "./songs/Backpack City.mp3"
},
{
"title": "Beauty",
"artist": "eyeroze",
"album": "Heartless",
"track": "4",
"year": "",
"img_src": "./songs_images/Beauty_Cover (front)_e.jpg",
"src": "./songs/Beauty.mp3"
},
{
"title": "Better Than He Can",
"artist": "Jennifer Flores",
"album": " Shiloh Dynasty",
"track": " LofiCentral",
"year": "All My Love",
"img_src": "./songs_images/Better Than He Can_Cover (front)_e.jpg",
"src": "./songs/Better Than He Can.mp3"
},
{
"title": "Break My Heart Again",
"artist": "90degrees",
"album": "Break My Heart Again",
"track": "1",
"year": "",
"img_src": "./songs_images/Break My Heart Again_Cover (front)_e.jpg",
"src": "./songs/Break My Heart Again.mp3"
},
{
"title": "Brightness",
"artist": "eyeroze",
"album": "Heartless",
"track": "15",
"year": "",
"img_src": "./songs_images/Brightness_Cover (front)_e.jpg",
"src": "./songs/Brightness.mp3"
},
{
"title": "Call me",
"artist": "90sFlav",
"album": "Collection",
"track": "1",
"year": "",
"img_src": "./songs_images/Call me_Cover (front)_e.jpg",
"src": "./songs/Call me.mp3"
},
{
"title": "Can We Kiss Forever?",
"artist": "Kina",
"album": " Adriana Proenza",
"track": "Can We Kiss Forever?",
"year": "1",
"img_src": "./songs_images/Can We Kiss Forever _Cover (front)_e.jpg",
"src": "./songs/Can We Kiss Forever .mp3"
},
]);
return (
<div className="App">
MusicPlayer
</div>
);
}
export default App;
现在,在 src 文件夹中,创建另一个名为 components 的文件夹,并在该文件夹中创建三个组件:Player、PlayerControls 和 PlayerDetails。
添加组件后,就该将 fontawesome 库安装到项目中了。只需将以下代码复制并粘贴到 package.json 和依赖项中,然后在集成终端中输入 npm install 即可。
"@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"@fortawesome/react-fontawesome": "^0.1.12",
另外,让我们在公共文件夹内的 index.html 文件中导入缩小版本的 fontawesome css CDN 链接。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"/>
您的最终 index.html 文件应该看起来与此有点类似。
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Lofi Muisc Player</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
让我们转到 PlayerControl 组件并添加以下代码。此组件将显示音乐播放器的控件。
// PlayerControls.js
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faPlay,
faPause,
faForward,
faBackward,
} from "@fortawesome/free-solid-svg-icons";
function PlayerControls(props) {
return (
<div className="music-player--controls">
<button className="skip-btn" onClick={() => props.SkipSong(false)}>
<FontAwesomeIcon icon={faBackward} />
</button>
<button
className="play-btn"
onClick={() => props.setIsPlaying(!props.isPlaying)}
>
<FontAwesomeIcon icon={props.isPlaying ? faPause : faPlay} />
</button>
<button className="skip-btn" onClick={() => props.SkipSong()}>
<FontAwesomeIcon icon={faForward} />
</button>
</div>
);
}
export default PlayerControls;
现在,让我们来看看 PlayerDetails 组件。这个组件会列出歌曲的所有详细信息
// PlayerDetails.js
import React from "react";
function PlayerDetails(props) {
return (
<div className="music-player--details">
<div className="details-img">
<img
className="details-img--image"
src={props.song.img_src}
alt={props.song.title}
/>
</div>
<div class="range"></div>
<div className="artist-info">
<h3 className="details-title">{props.song.title}</h3>
<h4 className="details-artist">{props.song.artist}</h4>
<div class="line"></div>
</div>
</div>
);
}
export default PlayerDetails;
最后,是时候更新我们的 Player 组件了。这将是我们应用程序运行的主要组件。第一步是导入 useState()、useRef()、useEffect() 以及我们之前创建的组件,并将其导入到我们的播放器组件中。
// Player.js
import React,{useState,useRef,useEffect} from 'react';
import PlayerDetails from "./PlayerDetails";
import PlayerControls from "./PlayerControls";
我们之前讨论过 useState() 钩子。
让我们深入研究 useEffect() 钩子。通过使用此钩子,你告诉 React 你的组件需要在渲染后执行某些操作。React 会记住你传递的函数(我们将其称为“效果”),并在执行 DOM 更新后调用它。为此,我们设置了文档标题,但我们也可以执行数据获取或调用一些其他命令式 API。将 useEffect() 放置在组件内部使我们可以直接从效果中访问 count 状态变量(或任何 props)。我们不需要特殊的 API 来读取它 - 它已经在函数作用域中。钩子拥抱 JavaScript 闭包,并避免在 JavaScript 已经提供解决方案的情况下引入特定于 React 的 API。useEffect() 钩子有点类似于我们所知道的类组件的生命周期方法。它在组件的每次渲染之后运行,包括初始渲染。因此,它可以被认为是 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。如果我们想要控制 effect 何时运行(仅在初始渲染时,或仅在特定状态变量发生变化时),我们可以将依赖项传递给 effect 来实现。此钩子还提供了一个清理选项,允许在组件销毁前清理资源。effect 的基本语法是: useEffect(didUpdate) 。
我们深入研究了 useState() 和 useEffect() hooks。那么,你可能会好奇“什么是 useRef() hooks?”
此钩子仅返回一个可变的 ref 对象,其 .current 属性(initialValue)为传入的参数。返回的对象将在组件的整个生命周期内保留。
const refContainer = useRef(initialValue);
让我们回到代码中。在 Player 组件内部,利用 useState() 和 useRef() 这两个钩子。
// Player.js
const audioElement = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
之后,利用 useEffect() 钩子实现暂停和播放功能
useEffect(() => {
if (isPlaying) {
audioElement.current.play();
} else {
audioElement.current.pause();
}
});
现在,创建一个实际跳过或转发歌曲的功能。
const SkipSong = (forwards = true) => {
if (forwards) {
props.setCurrentSongIndex(() => {
let temp = props.currentSongIndex;
temp++;
if (temp > props.songs.length - 1) {
temp = 0;
}
return temp;
});
} else {
props.setCurrentSongIndex(() => {
let temp = props.currentSongIndex;
temp--;
if (temp < 0) {
temp = props.songs.length - 1;
}
return temp;
});
}
}
最后,在return语句中添加以下代码。
<p>
<div className="text-anim">
<strong>Upcoming Song:</strong>
</div>
<div className="nextsong-details">
<img
src={props.songs[props.nextSongIndex].img_src}
alt={props.songs[props.nextSongIndex].title}
style={{ width: "4em", height: "auto" }}
/>
<p>
<b>{props.songs[props.nextSongIndex].title} </b> by
<b>{props.songs[props.nextSongIndex].artist}</b>
{/* from album
*/}
{/* <b>{props.songs[props.nextSongIndex].album}</b> */}
</p>
</div>
</p>
<div className="music-player">
<audio
src={props.songs[props.currentSongIndex].src}
ref={audioElement}
></audio>
<PlayerDetails song={props.songs[props.currentSongIndex]} />
<PlayerControls
isPlaying={isPlaying}
setIsPlaying={setIsPlaying}
SkipSong={SkipSong}
/>
<div class="player__footer">
<ul class="list list--footer">
<li>
<a href="#" class="list__link">
<i class="fa fa-heart-o"></i>
</a>
</li>
<li>
<a href="#" class="list__link">
<i class="fa fa-random"></i>
</a>
</li>
<li>
<a href="#" class="list__link">
<i class="fa fa-undo"></i>
</a>
</li>
<li>
<a href="#" class="list__link">
<i class="fa fa-ellipsis-h"></i>
</a>
</li>
</ul>
</div>
{/*
<h4>Lofi Music Player React </h4>
*/}
</div>
您的最终播放器组件应该看起来像这样。
//Player.js
import React, { useState, useRef, useEffect } from "react";
import PlayerDetails from "./PlayerDetails";
import PlayerControls from "./PlayerControls";
function Player(props) {
const audioElement = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
useEffect(() => {
if (isPlaying) {
audioElement.current.play();
} else {
audioElement.current.pause();
}
});
const SkipSong = (forwards = true) => {
if (forwards) {
props.setCurrentSongIndex(() => {
let temp = props.currentSongIndex;
temp++;
if (temp > props.songs.length - 1) {
temp = 0;
}
return temp;
});
} else {
props.setCurrentSongIndex(() => {
let temp = props.currentSongIndex;
temp--;
if (temp < 0) {
temp = props.songs.length - 1;
}
return temp;
});
}
};
return (
<>
<p>
<div className="text-anim">
<strong>Upcoming Song:</strong>
</div>
<div className="nextsong-details">
<img
src={props.songs[props.nextSongIndex].img_src}
alt={props.songs[props.nextSongIndex].title}
style={{ width: "4em", height: "auto" }}
/>
<p>
<b>{props.songs[props.nextSongIndex].title} </b> by
<b>{props.songs[props.nextSongIndex].artist}</b>
{/* from album
*/}
{/* <b>{props.songs[props.nextSongIndex].album}</b> */}
</p>
</div>
</p>
<div className="music-player">
<audio
src={props.songs[props.currentSongIndex].src}
ref={audioElement}
></audio>
<PlayerDetails song={props.songs[props.currentSongIndex]} />
<PlayerControls
isPlaying={isPlaying}
setIsPlaying={setIsPlaying}
SkipSong={SkipSong}
/>
<div class="player__footer">
<ul class="list list--footer">
<li>
<a href="#" class="list__link">
<i class="fa fa-heart-o"></i>
</a>
</li>
<li>
<a href="#" class="list__link">
<i class="fa fa-random"></i>
</a>
</li>
<li>
<a href="#" class="list__link">
<i class="fa fa-undo"></i>
</a>
</li>
<li>
<a href="#" class="list__link">
<i class="fa fa-ellipsis-h"></i>
</a>
</li>
</ul>
</div>
{/* <h4>Lofi Music Player React </h4> */}
</div>
</>
);
}
export default Player;
最后,是时候更新我们的 App.js 文件了。在 App.js 中添加双状态。
const [currentSongIndex,setCurrentSongIndex] = useState(0);
const [nextSongIndex,setNextSongIndex] = useState(currentSongIndex + 1);
创建一个功能,当当前歌曲结束时自动播放下一首歌曲。
useEffect(()=>{
setNextSongIndex(()=>{
if (currentSongIndex + 1 >songs.length - 1 ){
return 0;
} else{
return currentSongIndex + 1;
}
});
},[currentSongIndex])
最后,导入您的 Player 组件并使用以下道具返回它。
<Player currentSongIndex={currentSongIndex} setCurrentSongIndex={setCurrentSongIndex} nextSongIndex={nextSongIndex} songs={songs} />
最后,App 组件已锁定并准备就绪。App 组件内部的最终代码应如下所示。
// App.js
import React from 'react';
import {useState,useEffect} from "react";
import './App.css';
const App=()=> {
const [songs,setSongs] = useState([
{
"title": "$orries",
"artist": "Peachy!",
"album": " Shiloh",
"track": "$orries",
"year": "1",
"img_src": "./songs_images/$orries_Cover (front)_e.jpg",
"src": "./songs/$orries.mp3"
},
{
"title": "[oops]",
"artist": "potsu",
"album": "[oops]",
"track": "1",
"year": "",
"img_src": "./songs_images/[oops]_Cover (front)_e.jpg",
"src": "./songs/[oops].mp3"
},
{
"title": "5:32pm",
"artist": "The Deli",
"album": "Vibes 2",
"track": "12",
"year": "",
"img_src": "./songs_images/5 32pm_Cover (front)_e.jpg",
"src": "./songs/5 32pm.mp3"
},
{
"title": "88 Keys",
"artist": "Oatmello",
"album": "Snapshots",
"track": "3",
"year": "",
"img_src": "./songs_images/88 Keys_Cover (front)_e.jpg",
"src": "./songs/88 Keys.mp3"
},
{
"title": "Affection",
"artist": "Jinsang",
"album": "Life",
"track": "15",
"year": "",
"img_src": "./songs_images/Affection_Cover (front)_e.jpg ",
"src": "./songs/Affection.mp3"
},
{
"title": "Again",
"artist": "Wun Two",
"album": "Penthouse",
"track": "4",
"year": "",
"img_src": "./songs_images/Again_Cover (front)_e.jpg",
"src": "./songs/Again.mp3"
},
{
"title": "Alone and Lonely",
"artist": "prxz",
"album": " Shiloh Dynasty",
"track": "Love Wounds",
"year": "2",
"img_src": "./songs_images/Alone and Lonely_Cover (front)_e.jpg",
"src": "./songs/Alone and Lonely.mp3"
},
{
"title": "Baby You're Worth It",
"artist": "Kina",
"album": "Baby You're Worth It",
"track": "1",
"year": "",
"img_src": "./songs_images/Baby You're Worth It_Cover (front)_e.jpg",
"src": "./songs/Baby You're Worth It.mp3"
},
{
"title": "Backpack City",
"artist": "Flovry",
"album": " tender spring",
"track": "Ages Ago",
"year": "4",
"img_src": "./songs_images/ ",
"src": "./songs/Backpack City.mp3"
},
{
"title": "Beauty",
"artist": "eyeroze",
"album": "Heartless",
"track": "4",
"year": "",
"img_src": "./songs_images/Beauty_Cover (front)_e.jpg",
"src": "./songs/Beauty.mp3"
},
{
"title": "Better Than He Can",
"artist": "Jennifer Flores",
"album": " Shiloh Dynasty",
"track": " LofiCentral",
"year": "All My Love",
"img_src": "./songs_images/Better Than He Can_Cover (front)_e.jpg",
"src": "./songs/Better Than He Can.mp3"
},
{
"title": "Break My Heart Again",
"artist": "90degrees",
"album": "Break My Heart Again",
"track": "1",
"year": "",
"img_src": "./songs_images/Break My Heart Again_Cover (front)_e.jpg",
"src": "./songs/Break My Heart Again.mp3"
},
{
"title": "Brightness",
"artist": "eyeroze",
"album": "Heartless",
"track": "15",
"year": "",
"img_src": "./songs_images/Brightness_Cover (front)_e.jpg",
"src": "./songs/Brightness.mp3"
},
{
"title": "Call me",
"artist": "90sFlav",
"album": "Collection",
"track": "1",
"year": "",
"img_src": "./songs_images/Call me_Cover (front)_e.jpg",
"src": "./songs/Call me.mp3"
},
{
"title": "Can We Kiss Forever?",
"artist": "Kina",
"album": " Adriana Proenza",
"track": "Can We Kiss Forever?",
"year": "1",
"img_src": "./songs_images/Can We Kiss Forever _Cover (front)_e.jpg",
"src": "./songs/Can We Kiss Forever .mp3"
},
]);
const [currentSongIndex,setCurrentSongIndex] = useState(0);
const [nextSongIndex,setNextSongIndex] = useState(currentSongIndex + 1);
useEffect(()=>{
setNextSongIndex(()=>{
if (currentSongIndex + 1 >songs.length - 1 ){
return 0;
} else{
return currentSongIndex + 1;
}
});
},[currentSongIndex])
return (
<div className="App">
<Player currentSongIndex={currentSongIndex} setCurrentSongIndex={setCurrentSongIndex} nextSongIndex={nextSongIndex} songs={songs} />
</div>
);
}
export default App;
完整文章请见此处 => https://aviyel.com/post/1193
编码愉快!!
如果您是项目维护者、贡献者或只是开源爱好者,请关注@aviyelHQ或在 Aviyel 上注册以获得早期访问权限。
加入 Aviyel 的 Discord => Aviyel 的世界
推特 =>[ https://twitter.com/AviyelHq ]
文章来源:https://dev.to/aviyel/building-a-music-player-application-in-react-js-3ngd