I have a payment page, the user clicks on the button “PAY”, then a modal opens, it shows loading…, then it either renders the “payment success” component or the “payment failed” component.
When it renders any of the both, it plays a sound effect,
- on success, it plays the sound effect of CheckTennnn! ✅ “payment success”.
- on fail, it plays the sound effect of EEeerr.. ❌ “payment failed”.
The way I am implementing it is by having a useCallback which decides which view to render inside the modal, [success, or the fail view].
export default ProcessPaymentModal({ isSuccess, isError, isLoading }){
const [timer, setTimer] = useState(0)
useEffect(()=> {
const intervalId = setInterval(()=> setTimer((previousState)=> previousState + 1), 1000)
return ()=> clearInterval(intervalId)
})
const View = useCallback(()=>{
switch(true){
case isSuccess:
return <PaymentSuccessView timer={timer}/>
case isError:
return <PaymentFailView timer={timer}/>
case isLoading:
return <LoadingView />
}
}, [timer, isSuccess, isError, isLoading])
return <View />
}
And inside these fail or success components, I have that useEffect which plays the audio only once, on mount (and it must only play the sound once).
export default function PaymentSuccessView({ timer }) {
useEffect(() => {
const soundEffect = new Audio('../media/checktennn.mp3')
soundEffect.play()
}, []);
return <button> OK ({timer}) </button>;
}
Here’s a stack blitz instance, a code sandbox to test, (Click me)
However, the problem is that it keeps playing the sound every time the timer changes,
- CheckTennnn! ✅
- CheckTennnn! ✅
- CheckTennnn! ✅
Like this, you know.
Even though I have the dependency array empty in the <PaymentSuccessView />
component, which means this useEffect
function must only run once. On mount.