React 에러 - Maximum update depth exceeded

thisisyjin·2022년 4월 12일
0

Error Breaking 🔨

목록 보기
2/4

React로 가위바위보 웹게임을 제작하던 중,
Button을 클릭하면 onClickBtn 함수가 실행되도록 구현하는 과정에서 에러가 발생했다.


  • 컴포넌트가 반복적으로 setState를 호출 할 때
    -> componentWillUpdate나 componentDidUpdate 안에서.

위 상황에서 발생할 수 있는 오류라고 나온다.

그러나, 내가 작성한 코드에는 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>
profile
기억은 한계가 있지만, 기록은 한계가 없다.

0개의 댓글