はじめに
音声ファイルを動的に変更する必要があるアプリケーションを作成中に、以下のようなエラーに直面しました
"Uncaught (in promise) AbortError: The play() request was interrupted by a new load request."
自分がどのように解決したかを共有します。
問題の状況
実現したかったこと
- React を使って音声を動的に切り替える
- src を変更したら自動で再生する
初めのコード
const AudioComponent = ({ src }: { src: string }) => {
const audioRef = useRef<HTMLAudioElement>(null);
useEffect(() => {
if (audioRef.current) {
audioRef.current.src = src;
audioRef.current.play();
}
}, [src]);
return <audio ref={audioRef}></audio>;
};
これではエラーが出てしまいました
エラーの原因
1. audioRef.current.src = src
によって音声ファイルの URL が設定されると、ブラウザは自動的に音声リソースのロードを開始します。
このとき、以下のようなイベントが順番に発生します(一例)。
loadstart
progress
loadedmetadata
loadeddata
canplay
canplaythrough
2. 同時に audioRef.current.play()
を呼び出すと、まだ十分なデータを読み込めていない段階で再生要求が走るため、ブラウザが再生リクエストを中断 (abort) し、AbortError
が発生する場合があります。
解決方法
onLoadedData
イベントを利用して、リソースのロードが完了した後に再生を開始するように変更します。
onloadeddata
イベントが発生したタイミングでは、少なくとも 最初のフレームを再生できるだけのデータ が読み込まれています。そのため、このイベントより後に再生を開始すれば、AbortError の発生を防ぐことができます。
修正版コード
const AudioComponent = ({ src }: { src: string }) => {
const audioRef = useRef<HTMLAudioElement>(null);
useEffect(() => {
if (audioRef.current) {
audioRef.current.src = src;
}
}, [src]);
const handleLoadedData = () => {
if (audioRef.current) {
audioRef.current.play();
}
};
return <audio ref={audioRef} onLoadedData={handleLoadedData}></audio>;
};
結果
上記のコードに変更することで、AbortError
が発生せず、音声のソースを切り替えるたびに自動的に再生が始まるようになりました。
まとめ
音声や動画の動的な切り替えを扱う際には、onLoadedData
を活用して、リソースのロード完了後に再生を開始する方法が有効です。
もし誤りや補足があれば、ご指摘いただけると助かります。
参考