Les navigateurs évoluent et lancent de nouvelles API chaque année, nous aidant à créer des applications plus fiables et cohérentes sur le Web. Il y a quelques années, travailler avec de l'audio sur le Web était un travail assez difficile. Il n'y avait pas de bonnes API disponibles et les navigateurs offraient un support médiocre.
La lutte pour travailler avec l'audio est toujours réelle, en particulier dans les applications React. Il n'y a pas beaucoup de bonnes bibliothèques audio fiables avec lesquelles travailler dans React – la plupart ajoutent des difficultés à notre travail et ne fonctionnent pas comme nous voulons utiliser l'audio dans nos applications.
Nous avons quelques options pour travailler avec l'audio dans Applications JavaScript. Le plus connu et utilisé est Howler.js. Le seul problème avec Howler.js est qu'il n'a pas de wrapper React disponible, donc l'idée de l'intégrer dans votre application React peut devenir plus difficile et insoutenable en cours de route, et certains bogues et erreurs inattendus peuvent se produire.
A La solution que nous pouvons utiliser pour travailler avec l'audio dans les applications React consiste à créer notre propre bibliothèque audio React à l'aide d'une API native. Alors, apprenons-en plus sur le fonctionnement de l'API HTMLAudioElementpuis nous commencerons à créer notre propre bibliothèque audio React, afin que nous puissions facilement travailler avec l'audio dans nos applications React.
HTMLAudioElement[19659007]L'API HTMLAudioElement
est une interface qui permet d'accéder aux propriétés d'un
élément.
Il possède un constructeur appelé Audio()
qui reçoit une chaîne d'URL et renvoie un nouvel objet HTMLAudioElement
.
const audioElement = new Audio(src);[19659015]Le
HTMLAudioElement
n'a aucune propriété, mais il hérite des propriétés de l'interfaceHTMLMediaElement
.Le [L'interface
HTMLMediaElement
a une variété de différentes méthodes et propriétés avec lesquelles nous pouvons travailler pour créer quelque chose de vraiment utile. Par exemple, pour lire l'audio après avoir créé une nouvelle instance à l'aide du constructeurAudio()
il suffit d'utiliser la méthodeplay()
.audioElement .play();
Nous pouvons mettre en pause l'audio en utilisant la méthode
pause()
.audioElement.pause ();
L'interface
HTMLMediaElement
possède également de nombreux événements avec lesquels nous pouvons travailler, par exemple, leévénement chargé de données
. L'événementloadeddata
est déclenché une fois le chargement audio terminé.audioElement.addEventListener('loadeddata', (événement) => { console.log('Chargement terminé !'); });
Le
HTMLAudioElement
L'API nous aide à travailler avec l'audio en fournissant de nombreuses propriétés, méthodes et événements différents. Commençons par créer notre propre bibliothèque audio React en l'utilisant et voyons quel sera le résultat final. C'est pourquoi nous utiliserons TSDX.TSDX est une CLI sans configuration qui nous aide à créer facilement une nouvelle bibliothèque React, sans que nous ayons à configurer quoi que ce soit de plus. Nous utiliserons également npxqui est une CLI qui nous aide à installer et à gérer facilement les dépendances hébergées dans le registre npm.
Commençons le processus de création de notre bibliothèque audio React à l'aide de TSDX. Vous pouvez lui donner le nom que vous voulez. Dans votre console, donnez la commande suivante :
npx tsdx create audio-library
TSDX donne une belle structure pour commencer avec notre bibliothèque. Dans notre dossier src, nous avons notre fichier index.tsx, et nous pouvons supprimer tout ce qui se trouve dans ce fichier.
Dans notre fichier index.tsx, nous mettrons ce qui suit :
export { default as useAudio } from './useAudio';
Nous exporterons uniquement le fichier
useAudio
. Dans notre dossier src, créons notre fichieruseAudio.ts
. Ce fichier sera un hook React personnalisé, importons donc des hooks intégrés depuis React et créons notre fonction.import { useState, useCallback, useEffect, useRef } from "react"; const useAudio = ()[19659038]=> { ... } export default useAudio;
TSDX fournit par défaut une configuration TypeScript, alors utilisons-la . Nous allons créer une interface appelée
{ useState, useCallback, useEffect, useRef } de "react"[19659013];UseAudioArgs
qui sera les arguments que notre hookuseAudio
peut recevoir, puis la passer à notre hook personnaliséuseAudio
.[19659010]import
interface UtiliserAudioArgs {
src: chaîne;
précharge?: booléen;
lecture automatique?: booléen;
volume?: numéro;
muet?: booléen;
boucle?: booléen;
taux?: nombre;
}
const useAudio= ({
src,
précharge = true,
lecture automatique = faux,
volume = 0,5,
muet = faux,
boucle = faux,
taux = 1.0,
}: UseAudioArgs) => {
...
}[19659069]export default useAudio;
Maintenant, dans notre hook, utilisons le
useState
un hook intégré de React pour gérer notre état.[19659010]const [audio, setAudio] = useState<HTMLAudioElement | undefined> (undefined);
const [audioReady, setAudioReady] = useState<boolean>(false);
const [audioLoading, setAudioLoading] = useState<booléen>(true)[19659013];
const [audioError, setAudioError] = useState<string>( "")
const [audioPlaying, setAudioPlaying] = useState<boolean>(false);
const [audioPaused, setAudioPaused] = useState<boolean>(false);
const [audioDuration, setAudioDuration] = useState<nombre>(0);
const [ audioMute, setAudioMute] = useState<boolean>( false);
const [audioLoop, setAudioLoop] = useState<boolean>(false);
const [audioVolume, setAudioVolume] = useState<number>(volume);
const [audioSeek, setAudioSeek] = useState<number>(rate);
const audioRate, setAudioRate] = useState<number>(0)[19659013];
Nous aurons quelques états différents. Le
audioLoading
sera vrai par défaut, et nous le définirons surfalse
une fois l'audio chargé. Une fois que l'audio est chargé et queaudioLoading
estfalse
nous allons définiraudioReady
surtrue
afin que nous puissions identifier quand l'audio est prêt à jouer. En cas d'erreur, nous utiliserons l'étataudioError
.Créons également une référence appelée
audioSeekRef
que nous utiliserons à l'avenir pour mettre à jour notreaudioSeek
état.const audioSeekRef = useRef<number>();
Maintenant, allons créez une fonction appelée
newAudio
. Dans cette fonction, nous allons créer un nouvel objetHTMLAudioElement
à l'aide du constructeurAudio()
. De plus, nous allons définir certaines propriétés de notre nouvel objetHTMLAudioElement
en utilisant les arguments que nous avons reçus dans notre hookuseAudio
.Voici comment notre fonction
newAudio
ressemblera à :const newAudio = useCallback( ({ src, lecture automatique = faux, volume = 0,5, muet = faux, boucle = faux, rate = 1.0, }): HTMLAudioElement => { const audioElement = nouveau Audio(src); audioElement.autoplay = autoplay; audioElement.volume = volume; audioElement.muet = muet; audioElement.boucle = boucle; audioElement.playbackRate = rate; return audioElement; }, [][19659013]);
Ensuite, nous allons créer une fonction appelée
load
. Cette fonction se chargera de charger notre source audio et de changer notre état en écoutant les événements. Dans notre fonctionload
nous appellerons notre fonctionnewAudio
pour créer un nouvel objetHTMLAudioElement
.const load =[19659208]useCallback( ({ src, preload, autoplay, volume, muet , boucle, taux }) => { const newAudioElement = newAudio[19659013]({ src, précharge, lecture automatique, tome, muet, boucle, taux, }); }, [newAudio]);
À l'intérieur de notre
load
les premiers événements que nous écouterons sont les événementsabort
eterror
. En cas d'erreur, nous définirons notre étataudioError
sur un messageerror
.newAudioElement.addEventListener('abort ', () => setAudioError("Erreur!")); newAudioElement.addEventListener('error', () => setAudioError([196590or!]"Err "));
Maintenant, nous allons écouter l'événement
loadeddata
qui sera déclenché lorsque l'audio sera prêt à être lu. Dans notre fonction de rappel, nous vérifierons si l'argumentautoplay
est vrai. Si c'est le cas, l'audio sera lu automatiquement par défaut.newAudioElement.addEventListener('loadeddata', () => { if (autoplay) { setAudioLoading(false); setAudioReady[19659013](true); setAudioDuration(newAudioElement.duration); setAudioMute( muet); setAudioLoop(loop) setAudioPlaying(true);[19659210]} else { setAudioLoading(false); setAudioReady(true); setAudioDuration(newAudioElement.duration)[19659013]; setAudioMute(mute); setAudioLoop(loop); } });
Maintenant, les événements
play
etpause
. Chaque fois que l'audio est configuré pour être lu, nous définirons notre étataudioPlaying
surtrue
et notreaudioPaused
surfalse
. Nous ferons la même chose mais de manière inversée pour l'événementpause
.newAudioElement.addEventListener('play', () => { setAudioPlaying(true); setAudioPaused(false) ; }); newAudioElement.addEventListener('pause', () => { setAudioPlaying[1965139013]([1965959)]false); setAudioPaused(true); });
Le dernier événement que nous avons écoutera est l'événement
ended
. Dans la fonction de rappel de cet événement, une fois l'audio terminé, nous définirons tous nos états sur l'état par défaut.newAudioElement.addEventListener('ended'[19659013], () => { setAudioPlaying(false); setAudioPaused( false); setAudioSeek(0); setAudioLoading(false);[19659359]setAudioError(""); });
Maintenant, à la fin de notre fonction
load
, nous allons définir notre audio et passer lanewAudiofunction
en tant que dépendance de rappel. Si vous avez suivi toutes les étapes jusqu'ici, voici à quoi ressemblera notre fonctionload
:const load = useCallback(([19659013]{ src, preload, autoplay, volume, mute, loop taux }) => { const newAudioElement = newAudio({ src, précharge, lecture automatique, tome, muet, boucle, taux, }); newAudioElement.addEventListener('abort', () => setAudioError([19659035!]"Error ")); newAudioElement.addEventListener('error', () => setAudioError([196590or!]"Err ")); newAudioElement.addEventListener('loadeddata', () => { if (autoplay) { setAudioLoading(false); setAudioReady(true); setAudioDuration(newAudioElement.duration); setAudioMute(mute);[19659300]setAudioLoop(loop) setAudioPlaying(true); } else { setAudioLoading (false); setAudioReady(true); setAudioDuration(newAudio19Element[194590].duration); setAudioMute(mute); setAudioLoop(loop); } }); newAudioElement.addEventListener('play', () => { setAudioPlaying([19659131]true); setAudioPaused(false); }); newAudioElement.addEventListener('pause', () => { setAudioPlaying[1965139013]([1965959)]false); setAudioPaused(true); }); newAudioElement.addEventListener('ended', () => { setAudioPlaying[1965139013]([1965959)]false); setAudioPaused(false); setAudioSeek(0); setAudioLoading(false); setAudioError(""); }) 19659013]; setAudio(newAudioElement); }, [newAudio] ) ;
Maintenant, après avoir créé notre fonction
load
utilisons le hookuseEffect
pour charger notre audio.useEffect(([19659013]) => { if (!src) retour; if[19659037](!preload) return; load({ src, autoplay , volume, muet, boucle, taux }); },[19659037][src, preload, autoplay, volume, mute, loop , rate, load]);
Nous avons maintenant la partie la plus difficile de notre bibliothèque audio prête. Nous avons créé la fonction
newAudio
pour créer un nouvel objetHTMLAudioElement
et la fonctionload
pour charger notre audio. Il est maintenant temps de créer les fonctions que nous allons exporter dans notre hook, afin que nous puissions contrôler notre audio facilement.Nous allons commencer par créer une fonction appelée
onToggle
. Cette fonction va simplement lire l'audio ou le mettre en pause si l'audio est déjà en cours de lecture.const onToggle = () => { if (!audio) return; if (audioReady) audio.[19659019]play(); if (audioPlaying) audio.pause( ); };
Ensuite, nous allons créer les fonctions
onPlay
etonPause
.const onPlay = () => { if (!audio) retour; audio.play(); }; const onPause = ()[19659038]=> { if (!audio) retour; audio.pause(); };
Nous allons également créer une fonction appelée
onMute
pour couper notre audio et une autre fonction appeléeonLoop
pour boucler l'audio.const onMute = () => { if[19659037](!audio) retour; audio.muet = !audioMute; setAudioMute(!audioMute);[19659045]}; const onLoop = () => { if (!audio) retour; audio.loop = !audioLoop; setAudioLoop(!audioLoop);[19659045]};
Maintenant, nous allons créer les fonctions finales qui seront le
onVolume
pour changer notre volume,onRate
pour changer le taux de lecture de notre audio, etonSeek
pour modifier la recherche actuelle.const onVolume = (e: React.ChangeEvent <HTMLInputElement>) => { if (!audio) return[19659013]; const volume = parseFloat(e.cible.valeur) ; setAudioVolume(volume); audio.volume = volume; }; const onRate = (e: React.ChangeEvent<HTMLInputElement>) => { if ([19659098]!audio) return; const rate = parseFloat(e.cible .valeur); setAudioRate(rate); audio.playbackRate = rate; }; const onSeek = (e: React.ChangeEvent<HTMLInputElement>) => { if ([19659098]!audio) return; const seek = parseFloat(e.cible .value); setAudioSeek(seek); audio.currentTime = seek; };
Avant de finir de travailler sur notre hook
useAudio
nous ne pouvons pas oublier d'utiliser à nouveau le hookuseEffect
pour mettre à jour notreaudioSeek
en douceur à l'aide de l'APIrequestAnimationFrame
.useEffect(([19659013]) => { const animate = () => { const rechercher = audio?.currentTime; setAudioSeek(seek as nombre) ; audioSeekRef.current = requestAnimationFrame(animate); }; if (audio && lecture audio) { audioSeekRef.current = requestAnimationFrame(animate); } return ()[19659038]=> { if (audioSeekRef.current) { fenêtre.cancelAnimationFrame(audioSeekRef.current); } }; }[19659013], [audio, audioPlaying, audioPaused]);
Maintenant, à la fin de notre
useAudio
hook, retournons l'état et les fonctions dont nous aurons besoin dans notre bibliothèque audio.return { prêt: audioPrêt, chargement: audioChargement, erreur: audioError, lecture: audioLecture, en pause : audioEn pause, durée: audioDurée, muet: audioMuet, boucle: boucle audio, volume: audioVolume, chercher: audioRechercher, taux: taux audio, onToggle, onPlay, en pause, surMuet, en boucle, surVolume, surTaux, onSeek, }
Nous sommes maintenant prêts à tester et voir si tout fonctionne correctement. TSDX fournit un dossier appelé "Example", afin que nous puissions facilement importer notre hook
useAudio
et le tester.Usage
Dans notre dossier d'exemple, importons notre hook
useAudio
et commencez à jouer et utilisez-le comme un exemple réel.import { useAudio } from "../src"
Nous allons passer et utiliser audio simple avec notre hook
useAudio
et définissez quelques arguments par défaut.const { prêt, chargement, erreur, jouer, en pause, durée, muet, boucle, tome, chercher, taux, onToggle, onPlay, en pause, sur Muet, en boucle, surVolume, surTaux, onSeek, } = useAudio({ src, précharge : vrai, lecture automatique : faux, volume : 0,5, muet: faux, boucle : faux, rate: 1.0, });
Maintenant, dans notre composant, nous allons créer quelques boutons pour lire et mettre en pause notre audio.
retour ( <div> <bouton onClick={onToggle}>Toggle</button> <button onClick={onPlay}>Play</button> <button onClick={onPause}> Pause</button> </div> );
Also, let's create a few range inputs for our
seek
rate
andvolume
properties.return ( <div>[19659902]<button onClick={onToggle}>Toggle</button> <button onClick={onPlay}>Play</button> <button onClick={onPause}>Pause</button> <div> <label>Seek: </label> <input type="range" min={0} max={duration} value={seek} step={0.1} onChange={onSeek} /> </div> <div> <label>Volume: </label> <input type="range" min={0} max={1} value={volume} step={0.1} onChange={onVolume} /> </div> <div> <label>Rate: </label> <input type="range" min={0.25} max={5.0} value={rate} step={0.1} onChange={onRate} /> </div> </div> );
We now have our React audio library working pretty well. There’s a lot more we could do and implement in this library, like making use of the Context API so we can use our audio state logic in different components in our React tree, for example.
The HTMLAudioElement API is pretty powerful and simple to work with, and it allows us to create some incredible applications using audio on the web. In case you need something more sophisticated to work with audio, you can use the Web Audio APIwhich is similar but way more powerful and versatile to work with audio. You can use a few things like audio effects, sprites, audio visualizations and much more.
Conclusion
In this article, we learned about the HTMLAudioElement and created a React audio library using this powerful API. We used a few built-in React hooks for it and also created our own custom React hook, having a final result of a nice, simple and working React audio library ready for production that can be used in different ways.
Source link