• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Socket.io z nieznanej przyczyny resetuje hooki reacta

VPS Starter Arubacloud
+1 głos
329 wizyt
pytanie zadane 28 grudnia 2021 w JavaScript przez qax Dyskutant (8,060 p.)

Hej. Tuż przed świętami natknąłem się na dziwny problem z moją aplikcją, który ze względu na wolny czas chciałem dzisiaj rozwiązać i niestety chyba poniosłem porażkę bo brakuje mi już pomysłów i nie mam pojęcia co jest nie tak... laugh Otóż jakiś miesiąc temu wpadłem na pomysł napisania wieloosobowej gry w karty typu multiplayer. Chciałem lekko zakozaczyć i użyć technologii których wciąż się uczę. Oczywiście cały system oparłem na platformie Node.js plus protokół WebSocket a mianowicie bibliotekę Socket.IO. Back-end napisany w czystym JS ale jak już wspomiałem chciałem zakozaczyć i do front-endu użyłem Reacta. Jak do tej pory wszystko ładnie ze sobą działało - chciażby sam prymitywny czat działa normalnie ale jak już przyszła pora na rozpoczęcie gry i rozdanie kart wszystkim graczom - aplikacja wysypuje się. Po zbadaniu przyczyny okazuje się, że każdy gracz po otrzymaniu odpowiednich wiadomości z obiektami i tablicami zawierającymi niezbędne dane potrzebne do rozpoczęcia gry są PUSTE laugh i React próbuje zmapować chociażby talię kart (oczywiście dla każdego gracza inną) na podstawie pustych danych... Na froncie mam coś takiego:

function App() {
   const [playingRooms, setPlayingRooms] = useState([]);
   const [playersElapsedTime, setPlayersElapsedTime] = useState([]);
   useEffect(() => {
   socket.on('start-game', (data) => {
      console.log(data);
      setPlayingRooms(data.playingRooms);
      setPlayersElapsedTime(data.playersElapsedTime);
      setStartGameAlertClass('hidden');
      console.log(playingRooms);
      console.log(playersElapsedTime);
      //replacePlayers();
   });
   }, []);
   function startGame() {
      socket.emit('start-game', {playingRoomId: ownPlayingRoomId});
   }
}
return (
   // jsx...
);
export default App;

No i tak wygląda konsola w przeglądarce po rozpocząciu gry (wywołaniu funkcji startGame) - jak widać dane zostały wyemitowane do klientów przez serwer ale później po sprawdzeniu danych stanu Reacta są puste:

Odkomentowując linię //replacePlayers(), która umiejscawia graczy na ekranie wraz z ich kartami, React krzyczy:

No tak jakby po nadejściu wiadomości WebSocket dane stanu React Hooks były przywracane do pierwotnej postaci z nieznanej przyczyny (bo nigdzie indziej ich nie zmieniam). Może ktoś coś podpowie?

PS. Tak na marginesie dołączam jeszcze fragment back-endu w Node:

socket.on('start-game', (data) => {
		time = Date.now();
		let playingRoomId = parseInt(data.playingRoomId);
		let playerId = parseInt(playingRooms[playingRoomId].players.find(player => player.socketId === socket.id).playerId);
		let loginName = playingRooms[playingRoomId].players.find(player => player.socketId === socket.id).loginName.toString();
		let randomCardsDeck = [];
		playersElapsedTime = [];
		for (let loop = playingRooms[playingRoomId].lowestCard; loop <= 14; loop++) {
			for (let loop2 = 0; loop2 <= 3; loop2++) {
				randomCardsDeck.push([loop, loop2]);
			}
		}
		let cardsAmount = randomCardsDeck.length;
		let randomNumber = 0;
		let temp;
		while (cardsAmount--) {
			randomNumber = Math.floor(Math.random() * (cardsAmount + 1));
			temp = randomCardsDeck[cardsAmount];
			randomCardsDeck[cardsAmount] = randomCardsDeck[randomNumber];
			randomCardsDeck[randomNumber] = temp;
		}
		let cardsDeck = [];
		let ownCardsDeck = [];
		let socketId;
		for (let loop = 0; loop < 6; loop++) {
			playingRooms[playingRoomId].players.forEach(player => {
				if (typeof cardsDeck[player.playerId] === 'undefined') {
					cardsDeck[player.playerId] = [];
				}
				cardsDeck[player.playerId].push(randomCardsDeck.pop());
			});
		}
		playingRooms[playingRoomId].players.forEach(player => {
			ownCardsDeck = [];
			playersCardsDecks.push({playingRoomId: playingRoomId, playerId: player.playerId, cardsDeck: cardsDeck[player.playerId]});
			playingRooms[playingRoomId].players.find(player2 => player2.playerId === player.playerId).cardsAmount = cardsDeck[player.playerId].length;
			playersElapsedTime.push({playingRoomId: playingRoomId, playerId: player.playerId, time: playingRooms[playingRoomId].durationTime});
			for (let loop = 0; loop < cardsDeck[player.playerId].length; loop++) {
				cardsDeck[player.playerId][loop][2] = false;
				ownCardsDeck = cardsDeck[player.playerId];
			}
			socketId = playingRooms[playingRoomId].players.find(player2 => player2.playerId === player.playerId).socketId;
			io.to(socketId).emit('own-cards-deck', {ownCardsDeck: ownCardsDeck});
		});
		io.in(playingRoomId).emit('start-game', {playingRooms: playingRooms, playersElapsedTime: playersElapsedTime});
		console.log(currentTime(new Date(time)) + ' - Klient o nazwie użytkownika ' + loginName + ' rozpoczął grę w pokoju nr ' + (playingRoomId + 1));
	});

 

komentarz 28 grudnia 2021 przez elwood Gaduła (4,180 p.)
Sam miałem chyba podobny problem, jedyne rozwiązanie na jakie wpadłem to przepisanie componentu na classowy wtedy wszystko od razu zaczeło działać.

Chętnie poznam rozwiązanie dla hooków.
komentarz 29 grudnia 2021 przez qax Dyskutant (8,060 p.)

elwood dzięki za jakąkolwiek odpowiedź. To chyba musi być jakiś bug w krórejś z bibliotek, że nie chcą ze sobą współpracować, bo hooki to wciąż nowość w Reactcie. No cuż, czasami chce się użyć najnowocześniejszych technologii żeby ładnie wyglądały w portofolio, a trzeba z nich zrezygnować, żeby coś stworzyć mocniejszego... Spróbuję przepisać komonenty funkcyjne na klasowe tak jak podpowiadasz i zdam relację czy działa, tylko nie wiem jak użyć Socket.IO z komponentami klasowymi Reacta (wszędzie widziałem tylko tutoriale z hookami) - dlatego prosiłbym jeszcze o jakiś przykład (jak najbardziej może być w j. angielskim). Z góry dzięki. smiley

komentarz 29 grudnia 2021 przez elwood Gaduła (4,180 p.)
edycja 29 grudnia 2021 przez elwood

Nie jestem ekspertem od hooków, wiec nie wiem czy w tym twki problem.

Przepisz tylko komponent App jako klasowy i zobacz czy dane Ci poprawnie przychodzą, bo błąd może jest zupełnie gdzie indziej.

Przykładowo kod jaki wysłałeś mógłby wyglądać tak:

class App extends React.Component {

    state = {
        playingRooms: [],
        playersElapsedTime: []
    }
    //
    socket = io.connect({});

    componentDidMount() {
        this.socket.on('start-game', this.onStartGame);
    }

    onStartGame = (data) => {
        this.setState({
            playingRooms: data.playingRooms,
            playersElapsedTime: data.playersElapsedTime
        },()=>{
            console.log(playingRooms);
            console.log(playersElapsedTime);
            //replacePlayers();
        })
    }

    startGame() {
        this.socket.emit('start-game', {
            playingRoomId: ownPlayingRoomId
        });
    }

    render() {
        return // jsx
    }
}

export default App;

W razie czego postaram się pomóc.

komentarz 29 grudnia 2021 przez qax Dyskutant (8,060 p.)
Ok dzięki. ;)

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

+4 głosów
1 odpowiedź 270 wizyt
pytanie zadane 28 grudnia 2021 w Nasze projekty przez KopfSzmercen Bywalec (2,870 p.)
0 głosów
1 odpowiedź 752 wizyt
pytanie zadane 21 lutego 2017 w JavaScript przez Zainteresowany Nowicjusz (240 p.)
0 głosów
1 odpowiedź 297 wizyt
pytanie zadane 31 stycznia 2019 w JavaScript przez bergman Obywatel (1,600 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...