Today I Learned ... react.js
🙋♂️ React.js Lecture
🙋 My Dev Blog
React Lecture CH 5
1 - 라이프사이클
2 - setInterval과 라이프사이클 연동
3 - 가위바위보 게임
4 - 고차함수 (Higher-order Func)
5 - useEffect
6 - 클래스 vs Hooks 라이프사이클 비교
RSP.jsx
import React, { Component } from 'react';
const rspCoords = {
바위: '0',
가위: '-142px',
보: '-284px',
};
const scores = {
가위: 1,
바위: 0,
보: -1,
};
const computerChoice = (imgCoord) => {
return Object.entries(rspCoords).find(function (v) {
return v[1] === imgCoord;
})[0];
};
class RSP extends Component {
state = {
result: '',
score: 0,
imgCoord: '0',
};
interval;
componentDidMount() {
this.interval = setInterval(this.changeHand, 100);
}
componentWillUnmount() {
clearInterval(this.interval);
}
changeHand = () => {
const { imgCoord } = this.state;
if (imgCoord === rspCoords.바위) {
this.setState({
imgCoord: rspCoords.가위,
});
} else if (imgCoord === rspCoords.가위) {
this.setState({
imgCoord: rspCoords.보,
});
} else if (imgCoord === rspCoords.보) {
this.setState({
imgCoord: rspCoords.바위,
});
}
};
onClickBtn = (choice) => {
const { imgCoord } = this.state;
clearInterval(this.interval);
const myScore = scores[choice];
const cpuScore = scores[computerChoice(imgCoord)];
const diff = myScore - cpuScore;
if (diff === 0) {
this.setState({
result: '비겼습니다',
});
} else if ([-1, 2].includes(diff)) {
this.setState((prevState) => {
return {
result: '이겼습니다!',
score: prevState.score + 1,
};
});
} else {
this.setState((prevState) => {
return {
result: '졌습니다',
score: prevState.score - 1,
};
});
}
setTimeout(() => {
this.interval = setInterval(this.changeHand, 100);
}, 2000);
};
render() {
const { result, score, imgCoord } = this.state;
return (
<>
<div
id="computer"
style={{
background: `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${imgCoord} 0`,
}}
/>
<div>
<button
id="rock"
className="btn"
onClick={() => this.onClickBtn('바위')}
>
바위
</button>
<button
id="scissor"
className="btn"
onClick={() => this.onClickBtn('가위')}
>
가위
</button>
<button
id="paper"
className="btn"
onClick={() => this.onClickBtn('보')}
>
보
</button>
</div>
<div>{result}</div>
<div>현재 {score}점</div>
</>
);
}
}
export default RSP;
<변경 사항>
가위 : 1 , 바위 : 0, 보 : -1 이므로
1. 내가 이기는경우
- 바위로 이기면? -1
- 가위로 이기면? 2
- 보로 이기면? -1
✅ 이기는 경우에는 둘의 차이(diff)가 -1이나 2이다.
- 비기는 경우에는 차가 0이다.
- 지는 경우에는 else 처리.
참고 - includes 메서드 (Array.prototype)
[1,2,3,4,5].includes(2) // true
- true/false를 반환하므로 조건식으로 많이 사용됨.
const computerChoice = (imgCoord) => {
return Object.entries(rspCoords).find(function (v) {
return v[1] === imgCoord;
})[0];
};
예를 들어, '바위' 버튼을 눌렀다면?
현재 상태인 this.state.
const cpuScore = scores[computerChoice(imgCoord)];
이므로 현재 상태인 this.state.imgCoord를 인수로 받는다.
computerChoice 함수 내에서
Object.entries(rspCoords)는
const rspCoords = {
가위: '0',
바위: '-142px',
보: '-284px',
};
Object.entries(rspCoords);
// [['가위', '0'], ['바위', '-142px'], ['보', '-284px']]
위와 같이 Object.entries
로 rspCoords 객체의 키-값 쌍을 배열로 나타낸 후에,
Array.prototype.find()로 해당 콜백을 만족하는 첫번째 요소를 반환한다.
[['가위', '0'], ['바위', '-142px'], ['보', '-284px']]
.find(function (v) {
return v[1] === imgCoord;
})[0];
// 여기서 v는 배열의 각 요소를 의미함.
// v[1]은 두번째 요소가 imgCoord
// (=인수로 전달받은것. 즉, this.state (현재 상태))
// find()는 해당 요소를 반환하고,
// 뒤에 [0]을 붙여 첫번째 요소인 '가위' or '바위' or '보'를 반환.
Object.entries
- 참고 문서
- 객체 자체의 enumerable(순회가능) 속성의 key-value쌍 배열을 반환.
- cf> for...in은 프로토타입 체인의 속성도 열거하지만, entries는 자신의 속성만 열거함.
Array.prototype.find
- 참고 문서
- 인수로 판별 함수가 들어감.
- 만족하는 첫번째 요소의 값을 반환.
setTimeout(() => {
this.interval = setInterval(this.changeHand, 100);
}, 2000);
= Higher-order Function
// JSX
<button onClick={() => this.onClickBtn('바위')}>바위</button>
// onClickBtn 함수
onClickBtn = (choice) => {
// 함수 내용
}
위와 같이 '바위'라는 인수를 함수에 전달해주기 위해서는 함수를 실행하라는 의미에서
() =>
를 꼭 적어줘야 한다.
(안그러면 Error: Maximum update depth exceeded 가 발생)
-> 함수를 호출하는 호출부()가 있다면 에러 발생.
해결방법 - 고차함수 (커링)
onClickBtn = (choice) => () => { // () => () => ** 이중. // 함수 내용 } // JSX <button onClick={this.onClickBtn('바위')}>바위</button>
+) 참고
onClickBtn = (choice) => (e) => {
// 함수 내용
}
// JSX
<button onClick={this.onClickBtn('바위')}>바위</button>