Site icon Blog ARC Optimizer

Comment créer une bibliothèque audio React


Découvrez comment créer une bibliothèque audio React à l'aide de l'API HTMLAudioElement et utilisez-la dans vos projets.

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'interface HTMLMediaElement.

Le [L'interfaceHTMLMediaElement 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 constructeur Audio()il suffit d'utiliser la méthode play().

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énement loadeddata 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 fichier useAudio.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 UseAudioArgsqui sera les arguments que notre hook useAudio peut recevoir, puis la passer à notre hook personnalisé useAudio.[19659010]import

{ useState, useCallback, useEffect, useRef } de "react"[19659013];
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 useStateun 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 sur false une fois l'audio chargé. Une fois que l'audio est chargé et que audioLoading est falsenous allons définir audioReady sur trueafin que nous puissions identifier quand l'audio est prêt à jouer. En cas d'erreur, nous utiliserons l'état audioError.

Créons également une référence appelée audioSeekRefque nous utiliserons à l'avenir pour mettre à jour notre audioSeek état.

const audioSeekRef = useRef<number>();

Maintenant, allons créez une fonction appelée newAudio. Dans cette fonction, nous allons créer un nouvel objet HTMLAudioElement à l'aide du constructeur Audio(). De plus, nous allons définir certaines propriétés de notre nouvel objet HTMLAudioElement en utilisant les arguments que nous avons reçus dans notre hook useAudio.

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 fonction loadnous appellerons notre fonction newAudio pour créer un nouvel objet HTMLAudioElement.

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 loadles premiers événements que nous écouterons sont les événements abort et error. En cas d'erreur, nous définirons notre état audioError sur un message error.

newAudioElement.addEventListener('abort ', () => setAudioError("Erreur!"));
newAudioElement.addEventListener('error', () => setAudioError([196590or!]"Err "));

Maintenant, nous allons écouter l'événement loadeddataqui sera déclenché lorsque l'audio sera prêt à être lu. Dans notre fonction de rappel, nous vérifierons si l'argument autoplay 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 et pause. Chaque fois que l'audio est configuré pour être lu, nous définirons notre état audioPlaying sur true et notre audioPaused sur false. Nous ferons la même chose mais de manière inversée pour l'événement pause.

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 la newAudiofunction en tant que dépendance de rappel. Si vous avez suivi toutes les étapes jusqu'ici, voici à quoi ressemblera notre fonction load :

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 loadutilisons le hook useEffect 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 objet HTMLAudioElement et la fonction load 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 et onPause.

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ée onLoop 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, et onSeek 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 useAudionous ne pouvons pas oublier d'utiliser à nouveau le hook useEffect pour mettre à jour notre audioSeek en douceur à l'aide de l'API requestAnimationFrame.

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 seekrate and volume 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
Quitter la version mobile