Rock, Paper, Scissors | (NextJS,TailwindCSS,Framer Motion)
Design comparison
Solution retrospective
Hey! I'm Emre and this is my Rock,Paper,Scissors project
There are some problems with my project
- Score doesn't seem to be updating correctly
- Score takes negative values
I think the main problem is due to the use of useEffect
Any suggestions on how I can improve are welcome
GameContext.js
const onSelect = () => {
const userSelect = GameRules[selection].value;
const number = Math.floor(Math.random() * 3);
setHouseSelection(number);
setTimeout(() => {
setShow(true);
if (GameRules[houseSelection].beats.includes(userSelect)) {
setResult("You Lose");
setScore((score) => score - 1);
} else {
if (GameRules[houseSelection].value == userSelect) {
setResult("Tie");
} else {
setResult("You Win");
setScore((score) => score + 1);
}
}
}, 3000);
};
containers\game\index.js
const { onSelect, houseSelection, result, show, playAgain } =
useContext(GameContext);
useEffect(() => {
onSelect();
}, [houseSelection]);
Community feedback
- @11kylePosted about 1 year ago
Hey Emre! Great job on your solution! I checked into your question and have some feedback.
- Score takes a negative value.
This can be fixed by wrapping your
setScore((score) => score -1)
inside anif
statement like soif (score > 0) { setScore((score) => score - 1) }
- Score doesn't seem to be updating correctly
You are right on thinking it is the
useEffect
hook that is causing problems here.useEffect
gets called on initial render and again every time anything in the dependency array changes. You also never want to update anything from the dependency array from inside theuseEffect
. This could cause an infinite loop. In your case, theuseEffect
is running a minimum of 2 times and that is part of why you are seeing weird scores. The way your game is setup you can actually leave the dependency array empty like souseEffect(() => { onSelect(); }, []);
In addition, there's a weird thing happening with
useState
inside your GameContext.js.useState
actually takes 'time' to update its value. It's just a part of react. When you setState and then ask your function to do something with it, it is using the previous value. You can replacehouseSelection
withnumber
inside your function like soconst onSelect = () => { const userSelect = GameRules[selection].value; const number = Math.floor(Math.random() * 3); setHouseSelection(number); setTimeout(() => { setShow(true); if (GameRules[number].beats.includes(userSelect)) { setResult("You Lose"); setScore((score) => score - 1); } else { if (GameRules[number].value == userSelect) { setResult("Tie"); } else { setResult("You Win"); setScore((score) => score + 1); } } }, 3000); };
Marked as helpful1@rustysymPosted about 1 year ago@11kyle
Thank you for your feedback, Mark.
It was quite helpful in resolving this issue for me.
However, useEffect still continued to render twice, so I decided to use useRef to address the problem, and my issue was resolved.
const initialized = useRef(false); useEffect(() => { if (!initialized.current) { initialized.current = true; onSelect(); } }, []);
In addition to that, I restructured the code for
if (score > 0) { setScore((score) => (score ? score - 1 : 0));
so that the score no longer drops to negative values.1
Please log in to post a comment
Log in with GitHubJoin our Discord community
Join thousands of Frontend Mentor community members taking the challenges, sharing resources, helping each other, and chatting about all things front-end!
Join our Discord