React로 가위바위보 웹게임을 제작하던 중,
Button을 클릭하면 onClickBtn 함수가 실행되도록 구현하는 과정에서 에러가 발생했다.
위 상황에서 발생할 수 있는 오류라고 나온다.
그러나, 내가 작성한 코드에는 componentWillUpdate나 componentDidUpdater이 없었다.
그렇다면 이 오류는 왜 발생한건가?
아래는 내가 작성한 코드 전문이다.
(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;
정답은 바로,
JSX의 이벤트 프로퍼티에 인수를 전달한 함수를 호출하려면
() =>
를 적어줘야 하기 때문이다!
다시말해, 함수 자체를 전달?(X)
함수를 호출하여 전달(O)
cf>
예를 들면, input의 내용이 바뀔때마다 실행되는 함수는 인수를 전달해줄 필요가 없으므로
// JSX
<input value={this.state.value} onChange={this.onChangeInput} />
// onChangeInput
onChangeInput = (e) => {
this.setState({
value: e.target.value
});
}
이런식으로 함수 식별자만 전달해줬었다. (onChange 어트리뷰트의 값으로)
만약, 위에서 어트리뷰트에 ()와 함께 전달한다면?
<input value={this.state.value} onChange={this.onChangeInput()} />
-> onChangeInput을 호출
한 것이 됨.
(이벤트리스너에 함수를 전달한 것이 아니라,
함수를 호출한 셈)
함수를 호출한다 -> render()이 실행 -> 다시 함수를 부른다 -> 반복.
🔻
무한 루프가 되어서 depth를 초과했다는 에러가 뜬 것임.
+) 매개변수가 필요한 경우에도 ()가 호출부로 인식되므로 반드시 화살표 함수의 리턴값으로 넣어주자!
<button onclick={() => this.onClickBtn(param)}><button>