How to install audio in React? - reactjs

I am using a package called npm i --save react-audio-player and I am trying to use to have music auto play when the page is loaded. At this time, I am able to get the audio player to display, so the package is installed properly, however, the music does not show up at all.
I have had my audio directory both inside, and outside of the the project directory and I have copied the path directly from vscode, but it does not show to be active. Im not exactly sure what could possibly be causing this error. At first I thought maybe it was just chrome blocking the autoplay, but that would not explain why the audio file is displaying at all.
Below is both my code and a photo of my files
import React, {useState, useEffect} from 'react'
import ReactAudioPlayer from 'react-audio-player'
const App = () => {
// ======================================
// HOOKS
// ======================================
const [score, setScore] = useState(0)
const [showEZBake, setShowEZBake] = useState(false)
const [showToasterOven, setShowToasterOven] = useState(false)
const [showConvectionOven, setShowConvectionOven] = useState(false)
const [showSmallFactory, setShowSmallFactory] = useState(false)
// const [counter, setCounter] = useState(score)
// ======================================
// FUNCTIONS
// ======================================
const winCondition = () => {
if (score >= 100000) {
return (
<h1>YOURE A WINNER!!</h1>
)
}
}
// EARN REVENUE FUNCTIONS
const earn1 = () => {
setScore(score + 1)
winCondition()
}
const earn5 = () => {
setScore(score + 5)
winCondition()
}
const earn25 = () => {
setScore(score + 25)
winCondition()
}
const earn50 = () => {
setScore(score + 50)
winCondition()
}
const earn250 = () => {
setScore(score + 250)
winCondition()
}
// PURCHASE ITEMS FUNCTIONS
const buyEZOven = () => {
setScore(score - 25)
}
const buyToasterOven = () => {
setScore(score - 250)
}
const buyConvectionOven = () => {
setScore(score - 1000)
}
const buySmallFactory = () => {
setScore(score - 15000)
}
// THIS IS AN EXAMPLE OF HOW TO FORCE TEXT ONTO A PAGE
// const reveal = () => {
// // If the score is greater than or equal to 5, return the <h1> element
// if (score >= 5) {
// return (
// <h1>TEST</h1>
// )
// } else {
// // Otherwise, return null
// return null
// }
// }
const upgradeEZOven = () => {
if (score >= 25) {
setShowEZBake(true)
buyEZOven()
}
}
const upgradeToasterOven = () => {
if (score >= 250 ) {
setShowToasterOven(true)
buyToasterOven()
}
}
const upgradeConvectionOven = () => {
if (score >= 1000) {
setShowConvectionOven(true)
buyConvectionOven()
}
}
const upgradeSmallFactory = () => {
if (score >= 15000) {
setShowSmallFactory(true)
buySmallFactory()
}
}
// useEffect(() => {
// const timer = setInterval(() => {
// setCounter((prevCounter) => prevCounter + 1)
// }, 1000)
// return () => clearTimeout(timer);
// }, [counter, setCounter])
// ======================================
// DISPLAY
// ======================================
return (
<div>
<ReactAudioPlayer
src='../audio/mainMusic.mp3'
autoPlay
controls
/>
<h1>Bakery</h1>
<div className='header-grid-container'>
<h2>Revenue ${score}</h2>
<h2>Goal: $100,000</h2>
</div>
<div className='grid-container'>
{/* EZ BAKE OVEN */}
<img src="https://i.imgur.com/gDIbzJa.png" onClick={earn1}></img>
{showEZBake ? (
<img src="https://i.imgur.com/NQ0vFjF.png" onClick={earn5}></img>
) : (
<img onClick={upgradeEZOven} src="https://i.imgur.com/mwp9tL5.png"></img>
)}
{/* TOASTER OVEN */}
{showToasterOven ? (
<img src='https://i.imgur.com/k5m7lCM.png' onClick={earn25}></img>
) : (
<img src='https://i.imgur.com/hg12R4H.png' onClick={upgradeToasterOven}></img>
)}
{/* CONVECTION OVEN */}
{showConvectionOven ? (
<img src='https://i.imgur.com/JEzQkHL.png' onClick={earn50}></img>
) : (
<img src='https://i.imgur.com/x7i3ZeE.png' onClick={upgradeConvectionOven}></img>
)}
</div>
<div className='grid-container2'>
{showSmallFactory ? (
<img className='factory' src='https://i.imgur.com/HugCDVu.png' onClick={earn250}></img>
) : (
<img className='factory' src='https://i.imgur.com/HLsiH2r.png' onClick={upgradeSmallFactory}></img>
)}
{/* WIN CONDITION */}
{
winCondition()
}
{/* THIS IS AN EXAMPLE OF HOW TO CALL A FUNCTION
{
reveal()
} */}
</div>
</div>
)
}
export default App

Browsers does not allow pages to play audio unless there was a interaction done on the domain playing the sound. For Chrome this is the case since 2018.
Shown here: https://developer.chrome.com/blog/autoplay/
I am not familiar with package you are using, but I doubt it would change it. This means that you should not be able to play audio as soon as page is loaded and will have to force user to make any sort of interaction.
Aside from that I feel like the path is wrong. If you use those sort of relative paths and do not use import to get the resource they are in 90% instances resolved relative to public folder an project structure. So I'd try placing your audio folder into public and change src so that you are grabbing it relative to what browser sees. I sadly do not remember if that's public/audio/mainMusic.mp3 or audio/mainMusic.mp3or something else, but the simple test is, if you paste it into browser, it will either open, or start downloading the file.

Related

Can I generate a value per second with React?

Is there a way I can generate multiple SET VALUES per second using react?
What am I trying to accomplish?
I have created this "tap game" where you could generate $1 per tap up to $250 per tap depending on where you tap. In this game I want to be able to "hire employees." After designating the hired employee to, lets say "$1 team", my "Score" will increase by 1 per second. If I decided to hire another employee and I decided to assign it to "$5 team", it would increase by 5. Since I have 2 employees at this time, I do not want to cancel one or the other out, I would like them to run simultaneously (e.g. 6 per second in this example).
What Have I tried?
I have not tried, or tested, anything specifically because of course I am unsure of how to accomplish this. I have researched other Stack Overflow examples and I have came across one very similar, however, they are using an API where as I am not. Stack Overflow Example I am not sure if I would even need an API, I would assume I would not?
Request:
If at all possible, a solution that I could use dynamically would be extremely appreciated. If I decided to hire 10 employees and stick them all on $1 team, I would like to be able to do so.
Attached is a fully functional code.
import React, {useState, useEffect} from 'react'
const App = () => {
// ======================================
// HOOKS
// ======================================
const [score, setScore] = useState(0)
const [showEZBake, setShowEZBake] = useState(false)
const [showToasterOven, setShowToasterOven] = useState(false)
const [showConvectionOven, setShowConvectionOven] = useState(false)
const [showSmallFactory, setShowSmallFactory] = useState(false)
// ======================================
// FUNCTIONS
// ======================================
const winCondition = () => {
if (score >= 100000) {
return (
<h1>YOURE A WINNER!!</h1>
)
}
}
// EARN REVENUE FUNCTIONS
const earn1 = () => {
setScore(score + 1)
winCondition()
}
const earn5 = () => {
setScore(score + 5)
winCondition()
}
const earn25 = () => {
setScore(score + 25)
winCondition()
}
const earn50 = () => {
setScore(score + 50)
winCondition()
}
const earn250 = () => {
setScore(score + 250)
winCondition()
}
// PURCHASE ITEMS FUNCTIONS
const buyEZOven = () => {
setScore(score - 25)
}
const buyToasterOven = () => {
setScore(score - 250)
}
const buyConvectionOven = () => {
setScore(score - 1000)
}
const buySmallFactory = () => {
setScore(score - 15000)
}
const upgradeEZOven = () => {
if (score >= 25) {
setShowEZBake(true)
buyEZOven()
}
}
const upgradeToasterOven = () => {
if (score >= 250 ) {
setShowToasterOven(true)
buyToasterOven()
}
}
const upgradeConvectionOven = () => {
if (score >= 1000) {
setShowConvectionOven(true)
buyConvectionOven()
}
}
const upgradeSmallFactory = () => {
if (score >= 15000) {
setShowSmallFactory(true)
buySmallFactory()
}
}
// ======================================
// DISPLAY
// ======================================
return (
<div>
<h1>Bakery</h1>
<h2>Revenue {score}</h2>
<h3>No Bake Pudding</h3><button onClick={earn1}>$1</button>
{/* EZ BAKE OVEN */}
{showEZBake ? (
<>
<h3>Easy Bake Oven</h3>
<button onClick={earn5}>$5</button>
</>
) : (
<>
<h3>Purchase Easy Bake Oven</h3>
<button onClick={upgradeEZOven}>$25</button>
</>
)
}
{/* TOASTER OVEN */}
{showToasterOven ? (
<>
<h3>Toaster Oven</h3>
<button onClick={earn25}>$25</button>
</>
) : (
<>
<h3>Purchase Toaster Oven</h3>
<button onClick={upgradeToasterOven}>$250</button>
</>
)}
{/* CONVECTION OVEN */}
{showConvectionOven ? (
<>
<h3>Convection Oven</h3>
<button onClick={earn50}>$50</button>
</>
) : (
<>
<h3>Purchase Convection Oven</h3>
<button onClick={upgradeConvectionOven}>$1000</button>
</>
)}
{/* FACTORY */}
{showSmallFactory ? (
<>
<h3>Small Factory Production</h3>
<button onClick={earn250}>$250</button>
</>
) : (
<>
<h3>Purchase Small Factory</h3>
<button onClick={upgradeSmallFactory}>$15,000</button>
</>
)}
{/* WIN CONDITION */}
{
winCondition()
}
</div>
)
}
export default App
You can generate a value every second pretty easily with useEffect:
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setTimeout(() => {
setCount(count + 1);
}, 1000);
return () => clearTimeout(timer);
}, [count, setCount]);

How to swipe card programatticaly in react using react-tinder card

I am fetching data from the Backend and loading them in the card using react-tinder-card
Swiping works properly but unable to swipe using the buttons
I follow the documentation but still did not work
Here is the sample
Swiping gestures are working fine.
But when implement by checking documentation things did not work
Things are not working and tomorrow is my project day
import React, { useEffect, useState, useContext, useRef } from "react";
function Wink() {
const [people, setPeople] = useState([]);
const [loading, setLoading] = useState(false);
const [currentIndex, setCurrentIndex] = useState(people.length - 1)
const [lastDirection, setLastDirection] = useState()
// used for outOfFrame closure
const currentIndexRef = useRef(currentIndex)
const childRefs = useMemo(
() =>
Array(people.length)
.fill(0)
.map((i) => React.createRef()),
[]
)
const updateCurrentIndex = (val) => {
setCurrentIndex(val)
currentIndexRef.current = val
}
const canGoBack = currentIndex < people.length - 1
const canSwipe = currentIndex >= 0
// set last direction and decrease current index
const swiped = (direction, nameToDelete, index) => {
setLastDirection(direction)
updateCurrentIndex(index - 1)
}
const outOfFrame = (name, idx) => {
console.log(`${name} (${idx}) left the screen!`, currentIndexRef.current)
// handle the case in which go back is pressed before card goes outOfFrame
currentIndexRef.current >= idx && childRefs[idx].current.restoreCard()
// TODO: when quickly swipe and restore multiple times the same card,
// it happens multiple outOfFrame events are queued and the card disappear
// during latest swipes. Only the last outOfFrame event should be considered valid
}
const swipe = async (dir) => {
if (canSwipe && currentIndex < db.length) {
await childRefs[currentIndex].current.swipe(dir) // Swipe the card!
}
}
// increase current index and show card
const goBack = async () => {
if (!canGoBack) return
const newIndex = currentIndex + 1
updateCurrentIndex(newIndex)
await childRefs[newIndex].current.restoreCard()
}
useEffect(() => {
setLoading(true);
axios
.post("http://localhost:4000/api/all-profile", { email })
.then(function (response) {
setPeople(response.data);
setCurrentIndex(response.data.length);
}
}, []);
return (
<div className="DateMainDiv">
<Header />
<div className="ProfieCards">
{people.map((person) => (
<TinderCard
className="swipe"
key={person.email}
ref={childRefs[index]}
preventSwipe={swipe}
onSwipe={(dir) => swiped(dir, person.name, person.email)}
onCardLeftScreen={onCardLeftScreen}
onCardUpScreen={onCardUpScreen}
>
<div
style={{ backgroundImage: `url(${person.image})` }}
className="Winkcard"
>
<img
onLoad={handleLoad}
src={person.image}
alt="Image"
className="TinderImage"
/>
<h3>
{person.name}{" "}
<IconButton
style={{ color: "#fbab7e" }}
onClick={() => handleOpen(person.email)}
>
<PersonPinSharpIcon fontSize="large" />
{parseInt(person.dist/1000)+"KM Away"}
</IconButton>
</h3>
</div>
</TinderCard>
))}
<SwipeButtonsLeft onClick={()=>{swipe("left")}} />
<SwipeButtonsLeft onClick={()=>{goback()}} />
<SwipeButtonsLeft onClick={()=>{swipe("right")}} />
</div>
</div>
);
}
export default Wink;

Audio is not working properly after playing multiple time in ReactJS

I'm new to React and trying to add some audio to a tenzies game.
The audio is getting weirder every time I click the roll button. And after clicking for a while, the sound is fading away. There is also a warning in the console: 'The AudioContext was not allowed to start.'
I can't find out what causing this issue. Please help!
I don't know how to run react code in StackOverflow. So I'm adding a link to the github repository and live site URL of this game.
Here is the full App.js component's code:
import React from 'react';
import Die from './Components/Die';
import { nanoid } from 'nanoid';
import Confetti from 'react-confetti';
import {Howl} from 'howler';
import winSound from './audio/win.mp3';
import rollSound from './audio/roll.mp3';
import holdSound from './audio/hold.mp3';
export default function App(){
const [dice, setDice] = React.useState(generateNewDice());
const [tenzies, setTenzies] = React.useState(false);
const [audio, setAudio] = React.useState(true);
const [rollCount, setRollCount] = React.useState(0);
const [timer, setTimer] = React.useState(0);
const [timerRunning, setTimerRunning] = React.useState(false);
function holdDieObject(){
return {
value: Math.floor(Math.random()*6) + 1,
isHeld: false,
id: nanoid()
}
}
function generateNewDice(){
let newDice= [];
for(let i=0; i<10; i++){
newDice.push(holdDieObject());
}
return newDice;
}
React.useEffect(()=>{ //Count time per 10 milliseconds when timer is running
let interval;
if(timerRunning){
interval = setInterval(() => {
setTimer((prevTime) => prevTime + 10)
}, 10)
}else{
clearInterval(interval);
}
return () => clearInterval(interval);
},[timerRunning])
React.useEffect(()=>{ //Check all the dice are matched or not
const someDiceHeld = dice.some(die => die.isHeld);
const allDiceHeld = dice.every(die => die.isHeld);
const firstDiceValue = dice[0].value;
const allSameValue = dice.every(die=> die.value === firstDiceValue);
if(someDiceHeld){
setTimerRunning(true);
}
if(allDiceHeld && allSameValue){
setTenzies(true);
// audio && victorySound.play(); // This brings up dependency warning. So moved it to the bottom
setTimerRunning(false)
}
},[dice])
const victorySound = new Howl({
src: [winSound]
})
if(tenzies){
audio && victorySound.play(); // Here
}
const rollDieSound = new Howl({
src: [rollSound]
})
const holdDieSound = new Howl({
src: [holdSound]
})
function holdDice(id){
audio && holdDieSound.play();
setDice(oldDice => oldDice.map(die =>{
return die.id===id ?
{
...die,
isHeld: !die.isHeld
} :
die;
}))
}
function rollDice(){
if(!tenzies){
setDice(oldDice => oldDice.map(die=>{
audio && rollDieSound.play();
return die.isHeld ? die : holdDieObject();
}))
setRollCount(prevCount => prevCount + 1);
}else{
setTenzies(false);
setDice(generateNewDice());
setRollCount(0);
setTimer(0);
}
}
function toggleMute(){
setAudio(prevState => !prevState);
}
function startNewGame(){
setTenzies(false);
setDice(generateNewDice());
}
const minutes = <span>{("0" + Math.floor((timer / 60000) % 60)).slice(-2)}</span>
const seconds = <span>{("0" + Math.floor((timer / 1000) % 60)).slice(-2)}</span>
const milliseconds = <span>{("0" + ((timer / 10) % 100)).slice(-2)}</span>
const dieElements = dice.map((die) => {
return <Die key={die.id}
value={die.value}
isHeld={die.isHeld}
holdDice={()=> holdDice(die.id)}
/>
})
return(
<div>
<main className="board">
<button onClick={toggleMute} className="mute-btn">{audio ? "🔉" : "🔇"}</button>
<h1>Tenzies</h1>
<p>Roll untill the dice are the same. Click each die to freeze it at its current value between rolls.</p>
<div className="die-container">
{dieElements}
</div>
<button onClick={rollDice}>Roll</button>
{tenzies && <div className="scoreboard">
<h2>Congratulations!</h2>
<p className='rollCount'>Rolled: {rollCount}</p>
<p className="rolltime">Time Taken: {minutes}:{seconds}:{milliseconds}</p>
<h3>Your Score: 4500</h3>
<button className='close' onClick={startNewGame}>New Game</button>
</div>}
</main>
{tenzies && <Confetti className="confetti" recycle={false} />}
</div>
)
}

MediaSession Play/Pause button does not work in Chrome

I'm building a media controller application that controls a media player running in a remote process, and trying to use the MediaSession API to facilitate media key control. An audio element that is nearly silent is used to establish the media session, and after a few seconds it is paused indefinitely.
This works well in Firefox, but in Chrome-based browsers (desktop and mobile) the Play/Pause button does not change state and ultimately stops working after a few seconds. The Next/Previous track buttons work as expected.
What do I need to do to make the Play/Pause media session controls work in Chrome-based browsers?
React app to reproduce the issue:
import "./styles.css";
import React from "react";
export default function App() {
return (
<div className="App">
<h1>MediaSession demo</h1>
<Player />
</div>
);
}
function Player() {
const playctl = usePlayer();
if (playctl.state === "stopped") {
return <button onClick={playctl.playPause}>Begin</button>;
}
return (
<>
<p>Use media session notification to control player state.</p>
<MediaSession playctl={playctl} />
<p>Player state: {playctl.state}</p>
<p>Track: {playctl.track}</p>
</>
);
}
function usePlayer() {
const [state, setState] = React.useState("stopped");
const [track, setTrack] = React.useState(1);
let playing = state === "playing";
return {
playPause: () => {
playing = !playing;
setState(playing ? "playing" : "paused");
},
nextTrack: () => {
setTrack(track < 5 ? track + 1 : 1);
},
prevTrack: () => {
setTrack(track > 1 ? track - 1 : 5);
},
state,
nextState: playing ? "Pause" : "Play",
playing,
track
};
}
const MediaSession = ({ playctl }) => {
const controls = useMediaControls();
React.useEffect(() => controls.update(playctl), [controls, playctl]);
return controls.audio;
};
function useMediaControls() {
const audiofile = require("./near-silence.mp3");
const hasSession = window.navigator && "mediaSession" in window.navigator;
const ref = React.useRef();
let shouldShow = true;
function showControls(audio) {
shouldShow = false;
audio.volume = 0.00001; // very low volume level
audio.play();
audio.currentTime = 0;
// pause before track ends so controls remain visible
setTimeout(() => audio.pause(), 5000);
}
function updateSession(playctl) {
const session = window.navigator.mediaSession;
session.playbackState = playctl.playing ? "playing" : "paused";
session.setActionHandler("pause", playctl.playPause);
session.setActionHandler("play", playctl.playPause);
session.setActionHandler("nexttrack", playctl.nextTrack);
session.setActionHandler("previoustrack", playctl.prevTrack);
}
function createApi() {
return {
audio: hasSession && <audio ref={ref} src={audiofile} />,
update: (playctl) => {
if (hasSession) {
const audio = ref.current;
shouldShow && audio && showControls(audio);
updateSession(playctl);
}
}
};
}
return React.useState(createApi)[0];
}
Code sandbox: https://codesandbox.io/s/mediasession-demo-r773i

(reactjs) useEffect didn't run in background

I'm new to reactjs and and trying to make this simple stopwatch. this code is work in my browser, however when I minimize the browser the time paused, and only continue when I open the browser, do you found something I must be missed? Thanks in advance!
import { useState, useEffect } from "react";
export const SW = () => {
const [mSec, setMSec] = useState(0);
const [sec, setSec] = useState(0);
const [min, setMin] = useState(0);
const [isOn, setIsOn] = useState(false);
const start = () => setIsOn(true);
const stop = () => setIsOn(false);
const reset = () => {
setIsOn(false);
setMin(0);
setSec(0);
setMSec(0);
};
useEffect(() => {
let ms;
if (isOn) {
ms = setInterval(() => setMSec((mSec) => mSec + 1), 10);
if (sec === 59) {
setSec(0);
setMin((min) => min + 1);
}
if (mSec === 99) {
setMSec(0);
setSec((sec) => sec + 1);
}
}
return () => {
clearInterval(ms);
};
}, [mSec, sec, isOn]);
return (
<div>
<p>
{min.toString().padStart(2, "0")}:{sec.toString().padStart(2, "0")}:
{mSec.toString().padStart(2, "0")}
</p>
{!isOn && <button onClick={start}>{!mSec ? "start" : "resume"}</button>}
{isOn && <button onClick={stop}>stop</button>}
<button disabled={!mSec} onClick={reset}>
reset
</button>
</div>
);
};
It's not an issue on useEffect or your code, simply it's how browsers work, they execute JavaScript on the active tabs.
The solution is to use Web Workers API to execute JavaScript in the background.
For more details:
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
https://www.w3schools.com/html/html5_webworkers.asp

Resources