DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,274 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Building a music player application in react from absolute scratch πŸ”₯🎢
Pramit Marattha for Aviyel Inc

Posted on • Updated on • Originally published at aviyel.com

Building a music player application in react from absolute scratch πŸ”₯🎢

In this blog tutorial, we are going to set up and build music player applications using react.js from absolutely scratch.

There is an article specifically for you if you want to learn more about react.

React from absolute scratch

We will be building the UI and its functionalities from absolute ground level. However, before we begin, the final version of the app should look something like this.

demo

You can also check out the final live version of this application.

music-player-app-react.netlify.app

So, without any further ado let’s get this party started.

Installing react application

Let’s get started with our first react application. So the first thing you need to do is install Node.js if you don’t have it already installed on your system. So for that visit Node.js official site and install the correct and appropriate version. We need node js because we can utilize the node package manager or NPM feature.

mkdir

Now, create a blank folder and open it inside the code editor of your choice. For this tutorial, I will be using VScode. Next step, let’s open the integrated terminal and type npx create-react-app music-payer-react-app this command will create the app inside the current directory and that application will be named as music-payer-react-app

script illustration

create-react-app

It usually only takes a few minutes to install. Normally, when downloading packages, we would use npm to download them into the project, but here we are using npx, the package runner, which will download and configure everything for us so that we can begin with an amazing template.Now, It’s time to start our development server, so for that simply type npm start and that’s going to automatically open react-app in the browser.

react app

So, this is how the boilerplate template appears right away. Now it's time to investigate the file and folder structure provided by create-react-app. There is a folder called node module that contains all of our node dependencies. Then there's a public folder, where the only thing that matters is the index.html file. So this appears to be a standard HTML file, complete with head, body, and meta tags. You'll notice a div with the id root inside our body tag, followed by the fallback noscript tag, which will be visible only if the user's browser has javascript disabled.

<!--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>

Enter fullscreen mode Exit fullscreen mode

So you're probably wondering where the content comes from. Remember that, All of our source code is contained within our source or src folder, and react will inject it into the root div element. Let's take a look at our src folder, which contains some stylesheets, javascript files, and SVG files.

src directory

Now, head over to our App.js file

// 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;

Enter fullscreen mode Exit fullscreen mode

In this case, we're simply importing react from react and logo from our logo using standard javascript. Following that, we have a normal javascript function called APP, and this function in react is known as a functional component, and this function is returning a react-element that looks like HTML but is actually an jsx as you can see there is a div tag with a className of APP, and we can't say class by itself because the class is a reserved word in javascript, so in jsx we have to use className. Following that, we have the header and then the image, and notice on the image source that we have our logo, which is actually a javascript variable that we imported at the top, so in order to use the javascript within JSX, we must surround it with curly brackets, and then we have a paragraph, an anchor tag, and that is all for this component.

NOTE: Because of the export, we are able to extract the component and place it on the webpage. Export appears at the bottom of the app.js file, indicating that we are exporting the App function.

So, Now let's look at the index.js file.

// 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();

Enter fullscreen mode Exit fullscreen mode

So, in this case, we're importing react from react again, and this time we're also importing react-dom, and then we're importing the CSS stylesheet file, and finally, we're importing App from App.js, which is the file we just discussed, and there's service worker, which is used to make your application work completely offline. Then we invoke ReactDom.render, which accepts two parameters. The first parameter is the jsx object, and within jsx we can include our user-defined components, so react strict mode is a react defined component, whereas App is a user-defined component, and the second parameter is document.getElementById('root'), which targets the root div in our index.html file and is how we access the content in our webpage.

Note: ReactDom renders our content into our root div located at our index.html file.

Creating a music player application.

Let's create a simple music player application in react from the ground up, but first, let's create a prototype or mindmap of our final application.

So, our final app will look something like this.

prototype

Before we begin building our projects, we must first clean them up by removing some of the files provided by create-react-app. Your src files should look like this after you've cleaned them up.

Folder structure

Now, within the public folder, make another folder called songs,and songs_images and within that songs folder, add all the songs that you want and inside the songs_images add the cover images of that songs.

songs folder

songs image folder

All the songs and songs images are available for download from here

React-music-player-app (Github)

Now, go to your App.js file and create a useState() because this hook will enable us to integrate the state into our functional component. useState(), unlike state in class components, does not work with object values. If necessary, we can use primitives directly and create multiple react hooks for multiple variables.

const [state, setState] = useState(initialState);

useState() hook

Hooks in React must always be declared at the top of a function. This also aids in the preservation of state between all rendering for the component. Now change the songs initialization like the following illustration:

usestate demo

Copy and paste the code below into your App.js file.


// 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;

Enter fullscreen mode Exit fullscreen mode

Now, within the src folder, make another folder called components, and within that folder, make three components: Player, PlayerControls, and PlayerDetails.

components

After adding the component, it’s time to install fontawesome library to our project. So, for that simply copy and paste the following code in package.json and inside the dependencies and type npm install in your integrated terminal.

    "@fortawesome/fontawesome-svg-core": "^1.2.32",
    "@fortawesome/free-solid-svg-icons": "^5.15.1",
    "@fortawesome/react-fontawesome": "^0.1.12",

Enter fullscreen mode Exit fullscreen mode

package.json

and also, let’s import the minified version of fontawesome css CDN link in the index.html file located inside the public folder.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"/>

Enter fullscreen mode Exit fullscreen mode

Your final index.html file should look somewhat similar to this.

// 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>

Enter fullscreen mode Exit fullscreen mode

Let’s head over to our PlayerControl components and add the following code. This component will display the controls for the music player.


// 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;

Enter fullscreen mode Exit fullscreen mode

Now, let’s head over to our PlayerDetails components. This component will list out all the details of the Songs


// 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;

Enter fullscreen mode Exit fullscreen mode

Finally, it’s time to update our Player component. This will be the primary component through which we will make our application function. The first step is to import useState(),useRef(), useEffect(), and the components we previously created and import it within our player components.


// Player.js

import React,{useState,useRef,useEffect} from 'react';
import PlayerDetails from "./PlayerDetails";
import PlayerControls from "./PlayerControls";

Enter fullscreen mode Exit fullscreen mode

We discussed useState() hook previously.

react usestate

let’s dive into useEffect() hook.By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our β€œeffect”), and call it later after performing the DOM updates. To this effect, we set the document title, but we could also perform data fetching or call some other imperative API. Placing useEffect() inside the component lets us access the count state variable (or any props) right from the effect. We don’t need a special API to read it β€” it’s already in the function scope. Hooks embrace JavaScript closures and avoid introducing React-specific APIs where JavaScript already provides a solution.useEffect() the hook is somewhat similar to the life-cycle methods that we are aware of for class components. It runs after every render of the component including the initial render. Hence it can be thought of as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount.If we want to control the behavior of when the effect should run (only on initial render, or only when a particular state variable changes), we can pass in dependencies to the effect to do so. This hook also provides a clean-up option to allow cleaning up of resources before the component is destroyed. basic syntax of the effect: useEffect(didUpdate) .

useRef

We dived into useState() and useEffect() hooks. So, you might be wondering β€œwhat is useRef() hook ? β€œ.

This hook simply returns a mutable ref object with the passed argument as its.current property (initialValue). The returned object will be retained for the duration of the component's lifetime.

const refContainer = useRef(initialValue);

Enter fullscreen mode Exit fullscreen mode

Let us jump right back into the code. So, inside the Player component utilize the two hooks useState() and useRef() hooks.


// Player.js

const audioElement = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);

Enter fullscreen mode Exit fullscreen mode

After that, utilize the useEffect() hook to implement the pause and play functionality


useEffect(() => {
        if (isPlaying) {
            audioElement.current.play();
        } else {
            audioElement.current.pause();
        }
    });

Enter fullscreen mode Exit fullscreen mode

Now, Create a function that actually skips or forwards the songs.


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;
            });
        }
    }

Enter fullscreen mode Exit fullscreen mode

Finally, add the following code inside the return statement.

<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>&nbsp; by &nbsp;
      <b>{props.songs[props.nextSongIndex].artist}</b>
      {/* &nbsp; from album
      &nbsp; */}
      {/* <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>

Enter fullscreen mode Exit fullscreen mode

return

Your final Player component should look something like this.

//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>&nbsp; by &nbsp;
            <b>{props.songs[props.nextSongIndex].artist}</b>
            {/* &nbsp; from album
            &nbsp; */}
            {/* <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;

Enter fullscreen mode Exit fullscreen mode

Finally, it is time to update our App.js file. Inside App.js add two-state.

const [currentSongIndex,setCurrentSongIndex] = useState(0);
const [nextSongIndex,setNextSongIndex] = useState(currentSongIndex + 1);

Enter fullscreen mode Exit fullscreen mode

Create a feature that automatically plays the next song when the current one ends.


useEffect(()=>{
  setNextSongIndex(()=>{
  if (currentSongIndex + 1 >songs.length - 1 ){
    return 0;
  } else{
    return currentSongIndex + 1;
  }
});
},[currentSongIndex])

Enter fullscreen mode Exit fullscreen mode

Ultimately, import your Player component and return it with the following props.

<Player currentSongIndex={currentSongIndex} setCurrentSongIndex={setCurrentSongIndex} nextSongIndex={nextSongIndex} songs={songs} />

Enter fullscreen mode Exit fullscreen mode

Finally, the App component is locked and ready. The final code inside the app component should look something like this.


// 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;

Enter fullscreen mode Exit fullscreen mode

Full article available here => https://aviyel.com/post/1193

Happy Coding!!

Follow @aviyelHQ or sign-up on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.

Join Aviyel's Discord => Aviyel's world

Twitter =>[https://twitter.com/AviyelHq]

Top comments (6)

Collapse
 
lukeshiru profile image
Luke Shiru • Edited on

🀣 again with the "from absolute scratch". You might need to take a look at what that actually means. If you use a scaffolding tool such as create-react-app, you aren't starting "from scratch". Besides, the title is good and honest enough without that: "Building a music player app with React".

Collapse
 
midoukh profile image
Ahmed Khelili

From scratch refers to the player itself not how you set up your react project

Collapse
 
lukeshiru profile image
Luke Shiru

Still, a better fit would be "Building a music player application in React" ... saying "from scratch" is not necessary, and "from absolute scratch" is even more far fetched. Is like saying: "Building a house from nothing" and then the content is about the remodeling of a house that was already there. I don't mind the content in this post, the problem is the "false advertisement" in the title :/

Thread Thread
 
pramit_marattha profile image
Pramit Marattha Author

Thank you; I'll keep that in mind for the future articles.

Collapse
 
dineshamgoth profile image
Dinesh Amgoth

Atleast he's trying something

Collapse
 
luisreales profile image
luisreales

Very nice and very well explained

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post