I try to make a class to turn my react neater. and now use efffect or requestAnimation make my game controller disconect [closed]

my old gamePage look like this :

import React, { useEffect, useState, useRef } from 'react';
import GamepadManager from '../utils/GamepadManager';
import Stick from '../utils/Stick';
import PlatoTemplate from '../organisms/platoTemplate';
import mapConfigFile from '../assets/mapConfig/BepoStyle.json';
import '../styles/gamePage.css';
import LetterFall from '../organisms/LetterFall';
import { useDispatch, useSelector } from 'react-redux';
import { hit } from '../controler/lettersSlice';
import { addPrintableLetters } from '../controler/printableLettersSlice';

export default function GamePage() {
  const dispatch = useDispatch();
  const mapConfig = mapConfigFile;
  const letters = useSelector((state) => state.letters);
  const printableLetters = useSelector((state) => state.printableLetters);
  const lettersRef = useRef(letters);
  const [plato, setPlato] = useState(mapConfig.plato[0]);
  const [key, setKey] = useState('');
  const requestRef = useRef();
  let lastButtonPressed = [];

  useEffect(() => {
    lettersRef.current = letters;
  }, [letters]);

  useEffect(() => {
    lettersRef.current = printableLetters;
  }, [printableLetters]);

  useEffect(() => {
    const Gamepad = new GamepadManager();
    const leftStick = new Stick(0, 0);
    const rightStick = new Stick(0, 0);

    const selectPlato = ({ leftStickPosition, rightStickPosition }) => {
      const findedPlato = mapConfig.plato.find(plato => {
        return plato.joystick[0] === leftStickPosition && plato.joystick[1] === rightStickPosition;
      });
      setPlato(findedPlato);
      return findedPlato;
    };

    const selectKey = (curentPlato, buttonsPressed) => {
      const buttonPresse = buttonsPressed.findIndex(button => button === true);

      //je suis pas super fiere de mon systéme de gestion des input je me prendrais la tete dessus plus tard
      if (buttonPresse === -1) {
        lastButtonPressed = [];
      }
      if (buttonPresse === -1 || curentPlato === null || curentPlato === undefined) return;
      if (lastButtonPressed.includes(buttonPresse)) return;
      lastButtonPressed.push(buttonPresse);


      console.log(lettersRef.current);
      const keyPressed = curentPlato.KeyTab[mapConfig.buttonId[buttonPresse]];
      dispatch(hit(keyPressed));
      setKey(keyPressed);
    };

    const getGamepadsInfo = () => {
      const gamepadState = Gamepad.getState();
      if (gamepadState == null) return;

      leftStick.setDirection(gamepadState.axes[0], gamepadState.axes[1]);
      rightStick.setDirection(gamepadState.axes[2], gamepadState.axes[3]);

      const curentPlato = selectPlato({ leftStickPosition: leftStick.getDirection(), rightStickPosition: rightStick.getDirection() });
      selectKey(curentPlato, gamepadState.buttonsPressed);
    };

    const gameLoop = () => {
      getGamepadsInfo();
      requestRef.current = requestAnimationFrame(gameLoop);
    };

    requestRef.current = requestAnimationFrame(gameLoop);

    return () => cancelAnimationFrame(requestRef.current);
  }, [mapConfig]);

  const test = () => {
    console.log(letters);
  }

  const addPlato = (platoId) => {
    console.log(platoId);
    const plato = mapConfig.plato.find(plato => plato.id === platoId);
    //mettre les non selectionner en gris
    mapConfig.plato.forEach(plato => {
      plato.selected = false;
    });
    plato.selected = true;
    console.log(plato);
    Object.entries(plato.KeyTab).forEach(([buttonId, key]) => {
      if (key && key !== "void" && key !== "" &&
        !["Space", "Backspace", "Tab", "Enter", "Esc"].includes(key)) {
        if (key.length === 1) {
          dispatch(addPrintableLetters(key));
        }
        else if (key.length > 1) {
          dispatch(addPrintableLetters(key.slice(0, 1)));
        }
      }
    });
  }


  return (
    <div className='gamePage'>
      <button onClick={test}>test</button>

      <button onClick={addPlato}>test2</button>
      {plato != null ? <PlatoTemplate plato={plato} /> : null}
      <LetterFall />
      <div className='key'>{key}</div>

      <div className='score'>{letters.length}</div>
      <div className='map' onClick={() => console.log('click')}>
        {mapConfig.plato.map(plato =>
          <div
            className={plato.selected ? 'selected' : 'notSelected'}
            onClick={() => {
              console.log('Plato clicked:', plato.id);
              addPlato(plato.id);
            }}>
            <PlatoTemplate key={plato.id} plato={plato} />
          </div>
        )}
      </div>
    </div>
  );
}

and now i just replace all whit this :

import React, { useEffect, useState, useRef } from 'react';
import GamepadManager from '../utils/GamepadManager';
import Stick from '../utils/Stick';
import PlatoTemplate from '../organisms/platoTemplate';
import mapConfigFile from '../assets/mapConfig/BepoStyle.json';
import '../styles/gamePage.css';
import LetterFall from '../organisms/LetterFall';
import { useDispatch, useSelector } from 'react-redux';
import { hit } from '../controler/lettersSlice';
import { addPrintableLetters } from '../controler/printableLettersSlice';
import MapConfig from '../utils/MapConfig';


export default function GamePage() {
  const dispatch = useDispatch();

  const mapConfig = new MapConfig(mapConfigFile);
  const letters = useSelector((state) => state.letters);
  const printableLetters = useSelector((state) => state.printableLetters);
  const lettersRef = useRef(letters);
  const [plato, setPlato] = useState(mapConfig.platos[0]);
  const [key, setKey] = useState('');
  const requestRef = useRef();
  let lastButtonPressed = [];
  const lastTime = useRef(0);


  useEffect(() => {
    lettersRef.current = letters;
  }, [letters]);

  useEffect(() => {
    lettersRef.current = printableLetters;
  }, [printableLetters]);

  useEffect(() => {
    const Gamepad = new GamepadManager();
    const leftStick = new Stick(0, 0);
    const rightStick = new Stick(0, 0);

    const selectPlato = ({ leftStickPosition, rightStickPosition }) => {
      const findedPlato = mapConfig.platos[0] ;//mapConfig.platos.find(plato => plato.sameJostick([leftStickPosition, rightStickPosition]));
      setPlato(findedPlato);
      return findedPlato;
    };


    const selectKey = (curentPlato, buttonsPressed) => {
      const buttonPresse = buttonsPressed.findIndex(button => button === true);

      //je suis pas super fiere de mon systéme de gestion des input je me prendrais la tete dessus plus tard
      if (buttonPresse === -1) {
        lastButtonPressed = [];
      }
      if (buttonPresse === -1 || curentPlato === null || curentPlato === undefined) return;
      if (lastButtonPressed.includes(buttonPresse)) return;
      lastButtonPressed.push(buttonPresse);


      console.log(lettersRef.current);
      const keyPressed = curentPlato.keys[mapConfig.buttons[buttonPresse]];
      dispatch(hit(keyPressed));
      setKey(keyPressed);
    };

    const getGamepadsInfo = () => {
      const gamepadState = Gamepad.getState();
      if (gamepadState == null) return;
      leftStick.setDirection(gamepadState.axes[0], gamepadState.axes[1]);
      rightStick.setDirection(gamepadState.axes[2], gamepadState.axes[3]);

      const curentPlato = selectPlato({ leftStickPosition: leftStick.getDirection(), rightStickPosition: rightStick.getDirection() });
      selectKey(curentPlato, gamepadState.buttonsPressed);
    };

    const gameLoop = (timestamp) => {
      if (timestamp - lastTime.current >= 1000) { 
        console.log("timestamp:", timestamp)
        getGamepadsInfo(); 
        lastTime.current = timestamp;
      }
      requestRef.current = requestAnimationFrame(gameLoop);
    };

    requestRef.current = requestAnimationFrame(gameLoop);

    return () => cancelAnimationFrame(requestRef.current);
  }, [mapConfig]);


  const addPlato = (platoId) => {
    console.log(platoId);
    const plato = mapConfig.platos.find(plato => plato.id === platoId);
    //mettre les non selectionner en gris
    plato.selected = true;

    plato.keyList.forEach(key => {
      dispatch(addPrintableLetters(key));
    })
  }


  return (
    <div className='gamePage'>
      {plato != null ? <PlatoTemplate plato={plato} /> : null}
      <LetterFall />
      <div className='key'>{key}</div>

      <div className='score'>{letters.length}</div>
      <div className='map' >
        {mapConfig.platos.map(plato =>
          <div key={plato.id}
            className={plato.selected ? 'selected' : 'notSelected'}
            onClick={() => {
              addPlato(plato.id);
            }}>
            <PlatoTemplate key={plato.id} plato={plato} />
          </div>
        )}
      </div>
    </div>
  );
}

i replace requestAnimationFrame whit setTimeout and it work again . but i want to use requestAnimationFrame !

my MapConfig is just a setter

import Plato from "./PlatoHandler";

export default class MapConfig {

    constructor(mapConfig) {
        this.buttons = mapConfig.buttonId;
        this.platos = [];
        mapConfig.plato.forEach(plato => {
            this.platos.push(new Plato(plato));
        });
    }
}

and same for plato class

whit a litel extra if function

export default class Plato {

    constructor(plato) {
        this.id = plato.id;
        this.joystick = plato.joystick;
        //liste de touche mapper avec l'id des touches
        this.keys = plato.KeyTab;
        this.selected = false;

        //lister les touches
        this.keyList = []; 
        // Object.entries(plato.KeyTab).forEach(([buttonId, key]) => {
        //     if (key && key !== "void" && key !== "" &&
        //         !["Space", "Backspace", "Tab", "Enter", "Esc"].includes(key)) {
        //         this.keyList.push(key);
        //     }
        // });
    }

    sameJostick(joystick) {
        if (this.joystick[0] === joystick[0] && this.joystick[1] === joystick[1]) {
            return true;
        }
        return false;
    }
}

also i can show you my gamepadcontroller. is realy basic

export default class GamepadManager {
    /**
     * Initializes the GamepadManager object and sets up event listeners for gamepad connection and disconnection.
     * Also starts the gamepad loop to update the gamepad state at each frame.
     */
    controllerIndex = {
        index: null,
    };

    constructor() {

        window.addEventListener('gamepadconnected', (event) => {
            console.log('Gamepad connected:', event.gamepad);
            this.controllerIndex = event.gamepad.index;
        });

        window.addEventListener('gamepaddisconnected', (event) => {
            console.log('Gamepad disconnected:', event.gamepad);
            this.controllerIndex = null;
        });

    }

    updateGamepadState() {
        if (!this.gamepad) {
            return;
        }

        this.previousGamepadState = { ...this.currentGamepadState };
        this.currentGamepadState = {
            buttons: this.gamepad.buttons.map(button => button.pressed),
            axes: this.gamepad.axes.map(axis => axis.toFixed(2)),
        };
    }

    getState() {
        if (this.controllerIndex === null) return null;
        const gamepad = navigator.getGamepads()[this.controllerIndex];
        if (!gamepad) return null;

        return {
            buttonsPressed: gamepad.buttons.map(el => el.pressed),
            axes: gamepad.axes.map(axis => axis.toFixed(2)),
        };
    }

}

i will ad more funciton in this 2 class later and make game page litter .

i asking myself i am supose to do some

react return in class ?

so i can make a function to return this in mapConfig

<div className='map' >
        {mapConfig.platos.map(plato =>
          <div key={plato.id}
            className={plato.selected ? 'selected' : 'notSelected'}
            onClick={() => {
              addPlato(plato.id);
            }}>
            <PlatoTemplate key={plato.id} plato={plato} />
          </div>
        )}
      </div>

or we are not supos to use react like this ?