Reputation: 693
I am using functional components in react.
I have a Game component that is the display parent. It has a parent called Main which houses all the functions and variables for Game. I am getting the too many re-renders bug when I try to set the state of a particular variable. It is triggered by the startGame() method which calls an API and then calls another function with the data to set 4-6 variables. I can use the setState on 6 of the variables without issue but any time I try to 'setPlayers', it creates a too many re-renders bug.
I am clueless as to why this one variable is special. I temporarily solved the problem by switching Players to a regular variable at which point I can assign its value no problem but I would like to understand what's going on.
Main.jsx
let [isBet, setIsBet] = useState(false);
let [betOptions, setBetOptions] = useState();
let [hasStarted, setHasStarted] = useState(false);
let [id, setId] = useState(0);
const [players, setPlayers] = useState([]) ////The variable that causes the issue
// let players = []; //doesn't cause issue
const [cards, setCards] = useState([])
const [hand, setHand] = useState([])
const [betLog, setBetLog] = useState([])
const [showModal, setShowModal] = useState(false)
const [errorMessage, setErrorMessage] = useState("")
const setVariables= data => {
setHasStarted(true)
setId(data.gameId)
setPlayers(data.users) ///// !!!!! causes too many re-renders bug
// players = data.users // if I use this line instead of the above, the function works
// setPlayers([...data.users])
setHand(data.hand)
console.log("BET OPTIONS", data.betOptions)
if (data.betOptions.name === username){
setBet(data.betOptions)
}
}
const setBet = betOptions => {
setBetOptions(betOptions)
console.log("Your Bet Options are", betOptions)
console.log(betOptions.betAmount)
setIsBet(true)
}
const startGame = async (state) => {
let body = { username,
displayName : state.displayName,
numberOfPlayers : state.numberOfPlayers,
fillWithComputerPlayers: state.fillWithComputerPlayers,
isCustom: state.isCustom,
bigBlind: state.bigBlind
}
try {
const data = await Service.startGame(body);
console.log("response body", data.data)
setVariables(data.data);
} catch (err){
console.error(err)
setErrorMessage(err.message)
setShowModal(true)
setTimeout(function(){
setShowModal(false)
}, (2500))
}
}
All the variables are being used by the child component, Game. I am not using any UseEffect on 'players' but it is the only one of the relevant variables on which I am using a .map() (note- I am also mapping 'cards' and setting it in exactly the same way but in a different function). That is the only use of the 'players' variable.
Game.jsx
let id = props.id;
// let [players] = useState(props.players)
let players = props.players
let hand = props.hand;
let betOptions = props.betOptions;
let cards = props.cards
const [money, setMoney] = useState(0)
const username = props.username;
return (
<div id="background">
/// Lots of other components not relevant to the question
{props.hasStarted ?
<div>
{players.map((v, i) => { /////// !! only use of players
if (v.username !== username){
return (
<PlayerInfo name={v.username} money={v.money} key={i} class="info" />
)
} else {
setMoney(v.money)
}
})}
{cards.length > 0 && cards.map((v, i) => {
return (
<img className="cards" key={i} src={process.env.PUBLIC_URL + '/pics/PNG/' + v.image} alt={v.image} />
)
})}
<div id="my">
<MyInfo name={username} money={money} hand={hand} class="info" />
</div>
</div>
:
<SettingsForm startGame={props.startGame} username={username} />
}
</div>
<Log betLog={props.betLog} />
</div>
PlayerInfo.jsx
import "./Info.css"
const PlayerInfo = props => {
return (
<div className="info">
<h4>{props.name}</h4> {props.money}$
<div>
<img className="cards" src={process.env.PUBLIC_URL + '/pics/PNG/red_back.png'} alt="card" />
<img className="cards" src={process.env.PUBLIC_URL + '/pics/PNG/red_back.png'} alt="card" />
</div>
</div>
);
}
export default PlayerInfo;
Upvotes: 2
Views: 933
Reputation: 2525
Why not just turn as many of them as makes sense into 1 or more objects?
Unlike setState
for 5 different pieces of state, which would cause 5 separate re-renders,
setting the state as 1 object containing all those 5 pieces would cause only 1 re-render.
Upvotes: 2