I'm making a blackjack app, and I'm having trouble re-rendering hands after the initial hands. I'm trying to update my state in App.js and pass it to PlayerHand.js to be rendered, but the child component is not re rendering, even though a console.log shows that the state has been updated in App. Interestingly, if I hit ctrl-s in my text editor, PlayerHand.js will update, even if I haven't actually changed anything in the code.
App.js
function App() {
const [lobbyState, updateLobbyState] = useState('');
const [playerHand, updatePlayerHand] = useState([]);
//code that updates my state
const hit = () => {
socket.emit('hit', roomName, function(newCard){ hit
console.log('old player hand is ' + playerHand);
var newHand = playerHand;
newHand.push(newCard);
updatePlayerHand(newHand);
console.log('new player hand is ' + playerHand); //this shows a different hand than the first print statement
});
}
//renders initial hands; seems to be working, but included in case it's relevant
socket.on('initialHands', (data) => {
updateRoomName(data.roomName);
var newHand = data.playerHand;
updatePlayerHand(newHand);
updateOpponentHand(opponentHand.concat([data.opponentFirstCard, 'back']));
updateLobbyState('started');
})
switch(lobbyState){
case 'started':
return (
<div className="lobby">
<OpponentHand opponentHand = {opponentHand}/>
<PlayerHand playerHand = {playerHand} />
{currentPlayer ? <PlayerActions
hit={hit}
stand={stand}
/> : <h1> Not your turn </h1>}
</div>
)
case 'waiting':
return (
<Waiting />
)
default:
return (
<Home
createRoom={createRoom}
joinRoom={joinRoom}
/>
)
}
PlayerHand.js
import React, {useState, useEffect} from 'react';
import cards from './exports';
function PlayerHand (props){
const [hand, updateHand] = useState([]);
useEffect(() => {
var newHand = props.playerHand;
updateHand(newHand);
}, [props.playerHand]);
return (
<div>
{hand.map((card) => (<img src={cards[card]} alt="card" className="card"/>))}
</div>
)
}
export default PlayerHand;
Try:
const hit = () => {
socket.emit('hit', roomName, function(newCard){ hit
console.log('old player hand is ' + playerHand);
var newHand = [ ...playerHand ]; // <----- ***** THIS *******
newHand.push(newCard);
updatePlayerHand(newHand);
console.log('new player hand is ' + playerHand); //this shows a different hand than the first print statement
});
}
When you do var newHand = playerHand , you are actually never creating a new object, only a new reference. var newHand = [ ...playerHand ]; on the other hand (pun intended) does create a new object which causes state to change and a re-render.
Try updatePlayerHand(playerHand.concat(newCard)).
concat should be used instead of push with setState. I am not sure about useState hook though.