웹 게임을 만들며 배우는 React에서 실습했던 내용을 토대로 다시 만들어보는 가위바위보 게임
npx create-react-app react-rockpaperscissors
이미지를 쓰지 않아서 강의보다는 조금 간단하게 코드를 작성해보았다.
오브젝트명[키]
를 사용한다. button
에 disabled
속성을 주었다.btnDisabled
를 추가하고 버튼을 클릭하면 true
값을 주었다가 다시 재개가 될 때 false
로 변경되도록 하였다.import React, { useState, useRef, useEffect, useCallback } from 'react';
const scores = {
'✊': 1,
'✋': 0,
'✌': -1,
};
const RPS = () => {
const [computer, setComputer] = useState('✊');
const [user, setUser] = useState('🤘');
const [result, setResult] = useState('');
const [score, setScore] = useState(0);
const [btnDisabled, setBtnDisabled] = useState(false);
const interval = useRef(null);
const changeHand = useCallback(() => {
if (computer === '✊') {
setComputer('✋');
} else if (computer === '✋') {
setComputer('✌');
} else if (computer === '✌') {
setComputer('✊');
}
}, [computer]);
const onClickBtn = (user) => () => {
setUser(user);
setBtnDisabled(true);
clearInterval(interval.current);
const diff = scores[user] - scores[computer];
if (diff === 0) {
setResult('draw');
} else if ([-1, 2].includes(diff)) {
setResult('win');
setScore((prevScore) => prevScore + 1);
} else {
setResult('lose');
setScore((prevScore) => prevScore - 1);
}
setTimeout(() => {
interval.current = setInterval(changeHand, 100);
setBtnDisabled(false);
}, 1000);
};
useEffect(() => {
interval.current = setInterval(changeHand, 100);
return () => {
clearInterval(interval.current);
};
}, [changeHand]);
return (
<div>
<div>{computer}</div>
<div>{result}</div>
<div>{user}</div>
<div>
<button disabled={btnDisabled} onClick={onClickBtn('✊')}>
Rock
</button>
...
</div>
<div>Score: {score}</div>
</div>
);
};
export default RPS;
useCallback()
참고
렌더링 시 성능을 최적화하기 위해 사용하는 함수
- 함수형 컴포넌트는 렌더링마다 임의 메서드를 다시 재생성하는데, 이걸
useCallback()
으로 감싸고 종속성을 지정하면, 해당 종속성이 변경될 때만 새로운 함수를 생성하도록 한다. (함수의 레퍼런스를 기억하게 함)- 그래서
useEffect()
의 종속성으로useCallback()
함수를 사용하면 의존성 해결 완료....
(나 같은 경우 ESLint가useEffect()
안에 state를 변경하는 함수를 썼으니까 종속성에 함수를 추가하고 함수는useCallback()
으로 감싸라길래 그렇게 했다.... 어려워 🤪)