'How to resolve this reference error : Audio is not defined
Problem
I'm trying to play some audio files in some specific situations. e.g)
- When users access to login page, the audio plays 'Please enter your phone number'
- when an error message alert comes up, audio file is played such as 'your phone number has been already registered'
So far, the audio files are played successfully when you access some pages, but I got the reference error in the image after I added two lines of code below in the root component (app.tsx)
import {kioskAudio} from '../src/common/utils/kioskAudio';
const {playAudio, stopAudio} = kioskAudio();
What I've tried to resolve this issue
First try: I imported 'kioskAudio' method into KioskAlertError component directly. But I got the same reference error.
Second try: So I thought, 'Then should I import the 'kioskAudio' method to the root component(app.tsx) and deliver the props(playAudio, stopAudio) to the component like this :
<KioskAlertError playAudio={playAudio} stopAudio={stopAudio} />
But I still got the reference error. How can I resolve this issue?
Source Code
app.tsx
import KioskAlert, {IKioskAlertProps} from './component/KioskAlert';
import KioskAlertError from './component/KioskAlertError';
import {kioskAudio} from '../src/common/utils/kioskAudio';
export default function CustomApp({Component, pageProps}) {
const router = useRouter();
const [shouldStartRender, setShouldStartRender] = useState(false);
const [kioskAlertInfo, setKioskAlertInfo] = useState({isShow: false, onOK: null} as IKioskAlertProps);
const {playAudio, stopAudio} = kioskAudio();
useEffect(() => {
setShouldStartRender(true);
}, [router]);
return (
<>
<KioskAlertContext.Provider
value={{
kioskAlertState: kioskAlertInfo,
openKioskAlert: openKioskAlert,
closeKioskAlert: closeKioskAlert,
}}
>
<SWRConfig
value={{
refreshInterval: 0,
revalidateOnReconnect: true,
revalidateOnFocus: true,
onErrorRetry: (error, key, config, revalidate, {retryCount}) => {
if (error.response?.status === 401) {
localStorage.removeItem('accessToken');
return;
}
if (retryCount >= 5) return;
setTimeout(() => {
revalidate({retryCount});
}, 5000);
},
}}
>
{shouldStartRender ? (
<DomRouter>
<DomRoutes>
<DomRoute path="/home/home.html" element={<Home />} />
<DomRoute path="/home/clause.html" element={<Clause />} />
<DomRoute path="/home/loginPhone.html" element={<LoginPhone />} />
<DomRoute path="/home/loginPin.html" element={<LoginPin />} />
<DomRoute path="/home/signUp-phone.html" element={<SignUpPhone />} />
<DomRoute path="/home/signUp-authCode.html" element={<SignUpAuthCode />} />
<DomRoute path="/home/signUp-pin.html" element={<SignUpPin />} />
<DomRoute path="/home/CheckUserByPin.html" element={<CheckUserByPin />} />
</DomRoutes>
</DomRouter>
) : null}
<KioskAlertError playAudio={playAudio} stopAudio={stopAudio} />
<KioskAlert {...kioskAlertInfo} />
</SWRConfig>
</KioskAlertContext.Provider>
</>
);
}
KioskAudio.ts
export const kioskAudio = () => {
const audio = new Audio();
const playAudio = (folder: string, file: string) => {
stopAudio();
audio.setAttribute('src', `/sounds/${folder}/${file}.mp3`);
audio.play();
};
const stopAudio = () => {
audio.pause();
audio.currentTime = 0;
};
return {
playAudio,
stopAudio,
};
};
KioskAlertError.tsx
const KioskAlertError: React.FC<IKioskAlertErrorProps> = ({playAudio, stopAudio}) => {
const [isShow, setIsShow] = useState(false);
const [content, setContent] = useState('');
useEffect(() => {
document.addEventListener('error', (data: CustomEvent) => {
const message = JSON.parse(data.detail);
const errorMessage = message.message;
setContent(getErrorMessage(message.message));
setIsShow(true);
switch (errorMessage) {
case 'Already Registered':
console.log('Already joined');
playAudio('alert', '2');
break;
case 'Can't find your numbers':
console.log('userNotFound');
playAudio('alert', '1');
break;
}
});
return () => {
document.removeEventListener('error', null);
};
}, []);
const getErrorMessage = (messageCode) => {
return messageCode;
};
return isShow ? (
<Alert
content={content}
okText={'OK'}
onOK={() => setIsShow(false)}
wrapperStyle={defaultWrapperStyle}
alertStyle={defaultAlertStyle}
upperSectionStyle={defaultUpperSectionStyle}
lowerSectionStyle={defaultLowerSectionStyle}
titleStyle={defaultTitleStyle}
contentStyle={defaultContentStyle}
cancelStyle={defaultButtonStyle}
okStyle={defaultButtonStyle}
/>
) : null;
};
export default KioskAlertError;
Solution 1:[1]
As you have used the audio
variable inside your audio functions, the reference to the variable in function closures get lost between component re-renders. So you need to convert the kisokAudio
util into a custom hook which holds the ref between renders & then use useKioskAudio
instead of the simple function.
useKioskAudio.ts
import { useRef } from "react";
export const useKioskAudio = () => {
const audio = useRef(new Audio());
const playAudio = (folder: string, file: string) => {
stopAudio();
audio.current.setAttribute('src', `/sounds/${folder}/${file}.mp3`);
audio.current.play();
};
const stopAudio = () => {
audio.current.pause();
audio.current.currentTime = 0;
};
return {
playAudio,
stopAudio,
};
};
and then use it like
const { playAudio, stopAudio } = useKioskAudio();
in your app.tsx
component.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Sina |