#react-native dogcatoe tic-tac-toe game app with a cat vs dog theme sounds- Apk con una temática de gato contra perro con sonidos.

#react-native dogcatoe tic-tac-toe game app with a cat vs dog theme sounds- Apk con una temática de gato contra perro con sonidos.

Introduction - Introduction

App.tsx

import React, { useState  } from 'react';

import {
  FlatList,
  Pressable,
  SafeAreaView,
  StatusBar,
  StyleSheet,
  Text,  
  View,
} from 'react-native';

import Snackbar from 'react-native-snackbar';
import Icons from './components/Icons';;
import Sound from 'react-native-sound';

let globalSound: Sound | null = null; // Variable global para rastrear la instancia de sonido

function App(): React.JSX.Element {
  const [isCat, setIsCat] = useState<boolean>(false)
  const [gameWinner, setGameWinner] = useState<string>('')
  const [gameState, setGameState] = useState(new Array(9).fill('empty',0,9)) // llenar con 'empty' ,desde la posición 0, hasta la posición 9 sin incluirlo

  // Cargar archivos de audio
  const catSound = new Sound('cat.mp3', Sound.MAIN_BUNDLE, (error) => {
    if (error) {
      console.log('error al cargar cat.mp3', error);
      return;
    }
  });

  const dogSound = new Sound('dog.mp3', Sound.MAIN_BUNDLE, (error) => {
    if (error) {
      console.log('error al cargar dog.mp3', error);
      return;
    }
  });

  const gameSound = new Sound('game.mp3', Sound.MAIN_BUNDLE, (error) => {
    if (error) {
      console.log('error al cargar dog.mp3', error);
      return;
    }
  });



  const reloadGame = () => {
    if (globalSound)
     globalSound.stop();



    setIsCat(false)
    setGameWinner('')
    setGameState(new Array(9).fill('empty',0,9))

  }

  const checkIsWinner = () => {
    globalSound = gameSound;
    globalSound.play();
    //  checking  winner of the game

    if (
      gameState[0] === gameState[1] &&
      gameState[0] === gameState[2] &&
      gameState[0] !== 'empty'
    ) {
      setGameWinner(`${gameState[0]} won the game! 🥳`);
      if (gameState[0] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[0] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[3] !== 'empty' &&
      gameState[3] === gameState[4] &&
      gameState[4] === gameState[5]
    ) {
      setGameWinner(`${gameState[3]} won the game! 🥳`);
       if (gameState[3] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[3] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[6] !== 'empty' &&
      gameState[6] === gameState[7] &&
      gameState[7] === gameState[8]
    ) {
      setGameWinner(`${gameState[6]} won the game! 🥳`);
       if (gameState[6] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[6] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[0] !== 'empty' &&
      gameState[0] === gameState[3] &&
      gameState[3] === gameState[6]
    ) {
      setGameWinner(`${gameState[0]} won the game! 🥳`);
 if (gameState[0] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[0] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[1] !== 'empty' &&
      gameState[1] === gameState[4] &&
      gameState[4] === gameState[7]
    ) {
      setGameWinner(`${gameState[1]} won the game! 🥳`);
       if (gameState[1] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[1] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[2] !== 'empty' &&
      gameState[2] === gameState[5] &&
      gameState[5] === gameState[8]
    ) {
      setGameWinner(`${gameState[2]} won the game! 🥳`);
       if (gameState[2] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[2] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[0] !== 'empty' &&
      gameState[0] === gameState[4] &&
      gameState[4] === gameState[8]
    ) {
      setGameWinner(`${gameState[0]} won the game! 🥳`);
       if (gameState[0] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[0] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (
      gameState[2] !== 'empty' &&
      gameState[2] === gameState[4] &&
      gameState[4] === gameState[6]
    ) {
      setGameWinner(`${gameState[2]} won the game! 🥳`);
 if (gameState[2] === 'cat') {
        if(globalSound)
        globalSound.stop();
        globalSound = catSound;
        catSound.play();
      } else if (gameState[2] === 'dog') {
        if(globalSound)
        globalSound.stop();
        globalSound = dogSound;
        dogSound.play();
      }
    } else if (!gameState.includes('empty', 0)) { // para comenzar la busqueda desde el indice 0
      setGameWinner('Draw game... ⌛️');
    }

  }

  const onChangeItem = (itemNumber: number) => {
    if(globalSound){
      globalSound.stop();
      globalSound = gameSound;
      gameSound.play();
    }
    if(gameWinner){ 

      return Snackbar.show({
        text: gameWinner,
        backgroundColor: '#000000',
        textColor: '#FFFFFF'
      })


    }

    if(gameState[itemNumber]=== 'empty'){
      gameState[itemNumber] = isCat ? 'cat' : 'dog'
      setIsCat(!isCat)
    } else {
      Snackbar.show({
        text: "Position is already filled",
        backgroundColor: "red",
        textColor: "#FFF"

      })
    }
    checkIsWinner()
  }




  return (
    <SafeAreaView >
      <StatusBar   />
      {gameWinner ?  ( 
        <View style={[styles.playerInfo, styles.winnerInfo]}>

          <Text style={styles.winnerTxt}>{gameWinner}</Text>
        </View>
      ) : (
        <View 
        style={[
          styles.playerInfo,
          isCat ? styles.playerCat : styles.playerDog
        ]}>
          <Text style={styles.gameTurnTxt}>
            Player {isCat ? '😺' : '🐶'}'s Turn
          </Text>

        </View>
      )}
      { /* Game Grid */ }
      <FlatList 
      numColumns={3}
      data={gameState}
      style={styles.grid}
      renderItem={({item, index}) => (
        <Pressable
        key={index}
        style={styles.card}
        onPress={() => onChangeItem(index)}
        >
          <Icons name={item}  />
        </Pressable>
      )}
      />
      {/* game action */}
      <Pressable
      style={styles.gameBtn}
      onPress={reloadGame}
      >
        <Text style={styles.gameBtnText}>
          {gameWinner ?  'Start new game ' :  'reload the game'}
        </Text>
      </Pressable>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  playerInfo: {
    height: 56,

    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',

    borderRadius: 4,
    paddingVertical: 8,
    marginVertical: 12,
    marginHorizontal: 14,

    shadowOffset: {
      width: 1,
      height: 1,
    },
    shadowColor: '#333',
    shadowOpacity: 0.2,
    shadowRadius: 1.5,
  },
  gameTurnTxt: {
    fontSize: 20,
    color: '#FFFFFF',
    fontWeight: '600',
  },
  playerCat: {
    backgroundColor: '#EC4849',
  },
  playerDog: {
    backgroundColor: '#26ae60',
  },
  grid: {
    margin: 12,
  },
  card: {
    height: 100,
    width: '33.33%',

    alignItems: 'center',
    justifyContent: 'center',

    borderWidth: 1,
    borderColor: '#333',
  },
  winnerInfo: {
    borderRadius: 8,
    backgroundColor: '#38CC77',

    shadowOpacity: 0.1,
  },
  winnerTxt: {
    fontSize: 20,
    color: '#FFFFFF',
    fontWeight: '600',
    textTransform: 'capitalize',
  },
  gameBtn: {
    alignItems: 'center',

    padding: 10,
    borderRadius: 8,
    marginHorizontal: 36,
    backgroundColor: '#8D3DAF',
  },
  gameBtnText: {
    fontSize: 18,
    color: '#FFFFFF',
    fontWeight: '500',
  },
});

export default App;

Este código es para una aplicación de juego de tres en raya con una temática de gato contra perro.

Importa varios componentes de React Native como FlatList, Pressable, Text, etc para construir la IU.

La aplicación rastrea el estado del juego en la variable de estado gameState que se inicializa con todos los valores 'vacíos'.

Cuando se presiona una celda, el método onChangeItem actualiza el gameState estableciendo la celda en 'gato' o 'perro' según el turno que sea.

El método checkIsWinner verifica si hay un ganador en cada turno buscando tres en raya. Si hay un ganador, el estado gameWinner se actualiza.

También hay lógica para reproducir sonidos cuando se presionan las casillas o cuando hay un ganador usando la API Sound.

La IU muestra de quién es el turno, renderiza el tablero usando FlatList y tiene un botón de recarga para reiniciar el juego.

En general, tiene la lógica y los componentes necesarios para crear un juego interactivo de tres en raya con sonidos y retroalimentación visual.
This code is for a tic-tac-toe game app with a cat vs dog theme.

It imports various React Native components like FlatList, Pressable, Text, etc to build the UI.

The app keeps track of the game state in the gameState state variable which is initialized to all 'empty' values.

When a cell is pressed, the onChangeItem method updates the gameState by setting the cell to either 'cat' or 'dog' based on whose turn it is.

The checkIsWinner method checks if there is a winner every turn by checking for three in a rows. If there is a winner, the gameWinner state is updated.

There is also logic to play sounds when tiles are pressed or when there is a winner using the Sound API.

The UI shows whose turn it is, renders the board using a FlatList, and has a reload button to reset the game.

Overall, it has the logic and components to create an interactive tic-tac-toe game with sounds and visual feedback.

Icons.tsx

import React from 'react';
import type { PropsWithChildren } from 'react';
import Icon from 'react-native-vector-icons/FontAwesome5';

type IconsProps = PropsWithChildren<{ name: string }>;

const Icons = ({ name }: IconsProps) => {
  switch (name) {
    case 'cat': 
      return <Icon name="cat" size={50} color="#EC4849" />;
    case 'dog': 
      return <Icon name="dog" size={50} color="#26ae60" />;
    default:
      return <Icon name="pen" size={50} color="#0D0D0D" />;
  }
};

export default Icons;

Este código define un componente reutilizable de Icono que puede renderizar diferentes iconos de FontAwesome.

Importa React y el tipo PropsWithChildren de React. También importa el componente Icon desde la librería react-native-vector-icons.

Luego define un tipo llamado IconsProps que extiende PropsWithChildren y tiene una propiedad name que es un string. Esta será la interfaz de props para el componente Icons.

El componente funcional Icons toma props de tipo IconsProps. Desestructura sólo la propiedad name de esos props.

Dentro del componente hay una sentencia switch en la prop name. Dependiendo del nombre del icono pasado, devolverá un componente Icon desde react-native-vector-icons con algunas props predefinidas diferentes.

Finalmente, el componente se exporta como exportación por defecto. Así otros archivos pueden importar y usar el componente reutilizable Icons.

This code defines a reusable Icon component that can render different FontAwesome icons.

It imports React and the PropsWithChildren type from React. It also imports the Icon component from the react-native-vector-icons library.

It then defines a type called IconsProps which extends PropsWithChildren and has a name property that is a string. This will be the props interface for the Icons component.

The Icons functional component takes in props of type IconsProps. It destructures just the name property from those props.

Inside the component there is a switch statement on the name prop. Depending on the icon name passed in, it will return an Icon component from react-native-vector-icons with some different predefined props.

Finally, the component is exported as the default export. So other files can import and use the reusable Icons component.

Librerias - Libraries

Español:

react-native-vector-icons

  • Provee iconos y soporte de fuentes.

  • Para instalar: npm install react-native-vector-icons

react-native-snackbar

  • Muestra notificaciones snackbar.

  • Para instalar: npm install react-native-snackbar

react-native-sound

  • Reproduce archivos de sonido.

  • Para instalar: npm install react-native-sound

El comando para instalar es npm install <nombre-librería> para las 3 librerías. Esto las instalará localmente y las agregará como dependencias en el archivo package.json.

Adicionalmente, después de instalarlas con NPM, puede ser necesario hacer alguna configuración nativa. Las instrucciones de instalación se proporcionan en la documentación de cada una.

Inglés:

react-native-vector-icons

  • Provides icons and font support.

  • To install: npm install react-native-vector-icons

react-native-snackbar

  • Displays snackbar notifications.

  • To install: npm install react-native-snackbar

react-native-sound

  • Plays sound files.

  • To install: npm install react-native-sound

The command to install is npm install <library-name> for all 3 libraries. This will install them locally and add them as dependencies in the package.json file.

Additionally some native configuration may be needed after installing these libraries with NPM. The installation instructions are provided in their documentation.

github

dogcatoe github repository

youtube

Update App.tsx

import React, { useState, useEffect  } from 'react';

import {
  FlatList,
  Pressable,
  SafeAreaView,
  StatusBar,
  StyleSheet,
  Text,  
  View,
} from 'react-native';

import Snackbar from 'react-native-snackbar';
import Icons from './components/Icons';;
import Sound from 'react-native-sound';

let globalSound: Sound | null = null; // Variable global para rastrear la instancia de sonido

function App(): React.JSX.Element {
  const [isCat, setIsCat] = useState<boolean>(false)
  const [gameWinner, setGameWinner] = useState<string>('')
  const [gameState, setGameState] = useState(new Array(9).fill('empty',0,9)) // llenar con 'empty' ,desde la posición 0, hasta la posición 9 sin incluirlo
  const [catSound, setCatSound] = useState<Sound | null>(null);
  const [dogSound, setDogSound] = useState<Sound | null>(null);
  const [gameSound, setGameSound] = useState<Sound | null>(null);
  const [globalSound, setGlobalSound] = useState<Sound | null>(null); 

   useEffect(() => {
    const loadSounds = async () => {
      try {
        const catSoundInstance = new Sound('cat.mp3', Sound.MAIN_BUNDLE);
        const dogSoundInstance = new Sound('dog.mp3', Sound.MAIN_BUNDLE);
        const gameSoundInstance = new Sound('game.mp3', Sound.MAIN_BUNDLE);

        setCatSound(catSoundInstance);
        setDogSound(dogSoundInstance);
        setGameSound(gameSoundInstance);
      } catch (error) {
        console.log('Error al cargar los sonidos', error);
      }
    };

    loadSounds();
  }, []);


   useEffect(() => {
    return () => {
      catSound?.release();
      dogSound?.release();
      gameSound?.release();
    };
  }, [catSound, dogSound, gameSound]);

  const reloadGame = () => { 
   globalSound?.stop();    
    setIsCat(false)
    setGameWinner('')
    setGameState(new Array(9).fill('empty',0,9));

    // Iniciar la reproducción de gameSound cuando se reinicia el juego
  setGlobalSound(gameSound);
  gameSound?.play();

  }

  const checkIsWinner = () => {

    //  checking  winner of the game
   globalSound?.stop();
    if (
      gameState[0] === gameState[1] &&
      gameState[0] === gameState[2] &&
      gameState[0] !== 'empty'
    ) {
      setGameWinner(`${gameState[0]} won the game! 🥳`);
      if (gameState[0] === 'cat' && catSound) {        
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[0] === 'dog' && dogSound) {
        setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[3] !== 'empty' &&
      gameState[3] === gameState[4] &&
      gameState[4] === gameState[5]
    ) {
      setGameWinner(`${gameState[3]} won the game! 🥳`);
       if (gameState[3] === 'cat' && catSound) {
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[3] === 'dog' && dogSound) {
        setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[6] !== 'empty' &&
      gameState[6] === gameState[7] &&
      gameState[7] === gameState[8]
    ) {
      setGameWinner(`${gameState[6]} won the game! 🥳`);
       if (gameState[6] === 'cat' && catSound) {
       setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[6] === 'dog' && dogSound) {
        setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[0] !== 'empty' &&
      gameState[0] === gameState[3] &&
      gameState[3] === gameState[6]
    ) {
      setGameWinner(`${gameState[0]} won the game! 🥳`);
 if (gameState[0] === 'cat' && catSound) {
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[0] === 'dog' && dogSound) {
         setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[1] !== 'empty' &&
      gameState[1] === gameState[4] &&
      gameState[4] === gameState[7]
    ) {
      setGameWinner(`${gameState[1]} won the game! 🥳`);
       if (gameState[1] === 'cat' && catSound) {
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[1] === 'dog' && dogSound) {
        setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[2] !== 'empty' &&
      gameState[2] === gameState[5] &&
      gameState[5] === gameState[8]
    ) {
      setGameWinner(`${gameState[2]} won the game! 🥳`);
       if (gameState[2] === 'cat' && catSound) {
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[2] === 'dog' && dogSound) {
        setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[0] !== 'empty' &&
      gameState[0] === gameState[4] &&
      gameState[4] === gameState[8]
    ) {
      setGameWinner(`${gameState[0]} won the game! 🥳`);
       if (gameState[0] === 'cat' && catSound) {
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[0] === 'dog' && dogSound) {
       setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (
      gameState[2] !== 'empty' &&
      gameState[2] === gameState[4] &&
      gameState[4] === gameState[6]
    ) {
      setGameWinner(`${gameState[2]} won the game! 🥳`);
 if (gameState[2] === 'cat' && catSound) {
        setGlobalSound(catSound);
        catSound.play();
      } else if (gameState[2] === 'dog' && dogSound) {
        setGlobalSound(dogSound);
        dogSound.play();
      }
    } else if (!gameState.includes('empty', 0)) { // para comenzar la busqueda desde el indice 0
      setGameWinner('Draw game... ⌛️');
    }

  }

  const onChangeItem = (itemNumber: number) => {

    if(gameWinner){ 

      if ((
  gameState[0] === 'cat' || gameState[1] === 'cat' || gameState[2] === 'cat' ||
  gameState[3] === 'cat' || gameState[4] === 'cat' || gameState[5] === 'cat' ||
  gameState[6] === 'cat' || gameState[7] === 'cat' || gameState[8] === 'cat') && catSound
) {
    setGlobalSound(catSound);
    catSound.play();
} else if ((
  gameState[0] === 'dog' || gameState[1] === 'dog' || gameState[2] === 'dog' ||
  gameState[3] === 'dog' || gameState[4] === 'dog' || gameState[5] === 'dog' ||
  gameState[6] === 'dog' || gameState[7] === 'dog' || gameState[8] === 'dog') && dogSound
) {
    setGlobalSound(dogSound);
    dogSound.play();
}


      return Snackbar.show({
        text: gameWinner,
        backgroundColor: '#000000',
        textColor: '#FFFFFF'
      })


    }

    if(gameState[itemNumber]=== 'empty'){
      gameState[itemNumber] = isCat ? 'cat' : 'dog'
      setIsCat(!isCat)

    } else {
      Snackbar.show({
        text: "Position is already filled",
        backgroundColor: "red",
        textColor: "#FFF"

      })
    }
    checkIsWinner()
  }




  return (
    <SafeAreaView >
      <StatusBar   />
      {gameWinner ?  ( 
        <View style={[styles.playerInfo, styles.winnerInfo]}>

          <Text style={styles.winnerTxt}>{gameWinner}</Text>
        </View>
      ) : (
        <View 
        style={[
          styles.playerInfo,
          isCat ? styles.playerCat : styles.playerDog
        ]}>
          <Text style={styles.gameTurnTxt}>
            Player {isCat ? '😺' : '🐶'}'s Turn
          </Text>

        </View>
      )}
      { /* Game Grid */ }
      <FlatList 
      numColumns={3}
      data={gameState}
      style={styles.grid}
      renderItem={({item, index}) => (
        <Pressable
        key={index}
        style={styles.card}
        onPress={() => onChangeItem(index)}
        >
          <Icons name={item}  />
        </Pressable>
      )}
      />
      {/* game action */}
      <Pressable
      style={styles.gameBtn}
      onPress={reloadGame}
      >
        <Text style={styles.gameBtnText}>
          {gameWinner ?  'Start new game ' :  'reload the game'}
        </Text>
      </Pressable>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  playerInfo: {
    height: 56,

    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',

    borderRadius: 4,
    paddingVertical: 8,
    marginVertical: 12,
    marginHorizontal: 14,

    shadowOffset: {
      width: 1,
      height: 1,
    },
    shadowColor: '#333',
    shadowOpacity: 0.2,
    shadowRadius: 1.5,
  },
  gameTurnTxt: {
    fontSize: 20,
    color: '#FFFFFF',
    fontWeight: '600',
  },
  playerCat: {
    backgroundColor: '#EC4849',
  },
  playerDog: {
    backgroundColor: '#26ae60',
  },
  grid: {
    margin: 12,
  },
  card: {
    height: 100,
    width: '33.33%',

    alignItems: 'center',
    justifyContent: 'center',

    borderWidth: 1,
    borderColor: '#333',
  },
  winnerInfo: {
    borderRadius: 8,
    backgroundColor: '#38CC77',

    shadowOpacity: 0.1,
  },
  winnerTxt: {
    fontSize: 20,
    color: '#FFFFFF',
    fontWeight: '600',
    textTransform: 'capitalize',
  },
  gameBtn: {
    alignItems: 'center',

    padding: 10,
    borderRadius: 8,
    marginHorizontal: 36,
    backgroundColor: '#8D3DAF',
  },
  gameBtnText: {
    fontSize: 18,
    color: '#FFFFFF',
    fontWeight: '500',
  },
});

export default App;
  1. Declaración de Estados conuseState: Se definen cuatro estados con useState, cada uno representando una instancia de sonido diferente:

    • catSound para el sonido del gato.

    • dogSound para el sonido del perro.

    • gameSound para el sonido de fondo del juego.

    • globalSound para el sonido que se está reproduciendo actualmente.

Cada uno de estos estados tiene un valor inicial de null y una función para actualizar ese estado (setCatSound, setDogSound, etc.).

  1. State Declaration withuseState: Four states are declared using useState, each representing a different sound instance:

    • catSound for the cat sound.

    • dogSound for the dog sound.

    • gameSound for the background game sound.

    • globalSound for the currently playing sound.

  2. Primer useEffect: Este useEffect se ejecuta una vez cuando el componente se monta. Dentro de él, se define una función async llamada loadSounds que crea nuevas instancias de sonido y las carga en el estado correspondiente utilizando las funciones setCatSound, setDogSound y setGameSound. No se reproduce ningún sonido al cargarlos, lo cual es una práctica recomendada para evitar sorpresas al usuario.

    1. First useEffect: This useEffect runs once when the component mounts. Inside of it, an asynchronous function loadSounds is defined that creates new sound instances and loads them into the corresponding state using the setCatSound, setDogSound, and setGameSound functions. No sound is played upon loading, which is a recommended practice to avoid surprising the user.
     useEffect(() => {
        const loadSounds = async () => {
          try {
            const catSoundInstance = new Sound('cat.mp3', Sound.MAIN_BUNDLE);
            const dogSoundInstance = new Sound('dog.mp3', Sound.MAIN_BUNDLE);
            const gameSoundInstance = new Sound('game.mp3', Sound.MAIN_BUNDLE);

            setCatSound(catSoundInstance);
            setDogSound(dogSoundInstance);
            setGameSound(gameSoundInstance);
          } catch (error) {
            console.log('Error al cargar los sonidos', error);
          }
        };

        loadSounds();
      }, []);
  1. SegundouseEffect: Este useEffect se ejecuta cuando el componente se desmonta o cuando las dependencias (catSound, dogSound, gameSound) cambian. Su función de limpieza libera los recursos de los sonidos para prevenir fugas de memoria.

    3.SeconduseEffect: This useEffect runs when the component unmounts or when the dependencies (catSound, dogSound, gameSound) change. Its cleanup function releases the resources of the sounds to prevent memory leaks.

     useEffect(() => {
       return () => {
         catSound?.release();
         dogSound?.release();
         gameSound?.release();
       };
     }, [catSound, dogSound, gameSound]);