강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

Bell Vise님의 프로필 이미지
Bell Vise

작성한 질문수

웹 게임을 만들며 배우는 React

비동기 작업 해제에 대해

해결된 질문

작성

·

317

·

수정됨

0

    interval

    componentDidMount() { 
        this.interval = setInterval(this.changeHand, 100) 
    }

    componentDidUpdate() { 

    }

    componentWillUnmount() { 
        clearInterval(this.interval)
    }

onClickBtn = (choice) => {
        clearInterval(this.interval)
        const {imgCoord} = this.state
        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} 0px` }} />
      <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>
    </>

강의에서 제로초님이 가위바위보 컴포넌트는 제거를 안하기 때문에 componentWillUnmount()를 넣으나 안넣으나 상관이 없다는식으로 얘기를 했습니다.

그러나 componentWillUnmount()에 clearInterval를 안넣게되면 componentDidMount()에서 생성된 this.interval라는 비동기작업이 onClickBtn 함수에서 clearInterval로 해제가 안됩니다.

왜 그런지 이유가 궁금합니다.

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

강의에서 제로초님이 가위바위보 컴포넌트는 제거를 안하기 때문에 componentWillUnmount()를 넣으나 안넣으나 상관이 없다는식으로 얘기를 했습니다.

제가 언제 이런 말을 했나요..? 했다 해도 그 맥락이 아니었을텐데요?

setInterval이 있으면 당연히 componentWillUnmount에서 해제해야 합니다.

Bell Vise님의 프로필 이미지
Bell Vise
질문자

5-3. 가위바위보 만들기에서 9분쯤에 componentWillUnmount() 넣으나 안넣으나 체감하기 힘들다. 가위바위보 컴포넌트를 제거를 안하기 때문인데 자식컴포넌트가 됐을 때는 꼭 넣어줘야 메모리 누수 문제를 안겪을 수 있다. 이렇게 말씀하셨는데 말씀대로

componentWillUnmount()는 컴포넌트가 제거되기 직전에 실행되니까 가위바위보 컴포넌트는 제거되는 경우가 브라우저를 종료했을 때 말고는 없기 때문에 componentWillUnmount() 없애고 그냥 setInterval을 onClickBtn함수에서 clearInterval 해도 이론적으로 되지 않을까요?

근데 componentWillUnmount()는 실행될 일이 없음에도 왜 언마운트에 clearInterval을 해야하는지 궁금합니다. 또 언마운트에 clearInterval을 안하게 되면 onClickBtn함수로는 왜 비동기 작업이 해제가 안되는지 궁금해요.

 

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

근데 componentWillUnmount()는 실행될 일이 없음에도 왜 언마운트에 clearInterval을 해야하는지 궁금합니다.

네 브라우저를 종료할 때를 제외하고는 unmount가 될 일이 없는 컴포넌트에서는 componentWillUnmount에서 clearInterval을 안 해도 됩니다. 다만 항상 unmount에서 clear하는 습관을 들이는 게 좋습니다.

그냥 setInterval을 onClickBtn함수에서 clearInterval 해도 이론적으로 되지 않을까요?

onClickBtn함수에서는 왜 clearInterval을 하나요? 지금 unmount쪽과 완전히 다른 맥락으로 이야기하시는 건가요? 가위바위보가 돌아가는 걸 멈추는 걸 말씀하시는 거면 onClickBtn에서 clearInterval하는 게 맞습니다. unmount쪽은 아예 컴포넌트를 언마운트할 때 clear하기위해서 하는 거고요.

언마운트에 clearInterval을 안하게 되면 onClickBtn으로는 비동기 작업이 해제가 왜 안되는지 궁금해요.

해제가 됩니다. 언마운트랑 상관이 없어요.

지금 onClickBtn에서 clearInterval하는 것과 componentWillUnmount에서 clearInterval하는 것이 왜 한 질문에 같이 나오는지 이해를 못 하겠습니다.

Bell Vise님의 프로필 이미지
Bell Vise
질문자

image

gif 사진을 가져와봤습니다.

onClickBtn 함수에 clearInterval이 있음에도 componentWillUnmount()에 clearInterval를 안쓰게 되면 onClickBtn 함수에 clearInterval은 작동이 안됩니다.

소스코드 전문입니다.

import React, { Component } from 'react'

// 클래스의 경우 -> constructor -> render -> ref -> componentDidMount
// (setState/props 바뀔때) -> shouldComponentUpdate(true) -> render -> componentDidUpdate
// 부모가 나를 없앴을 때 -> componentWillUnmount -> 소멸

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 RPSClass extends Component {
    state = {
        result : '',
        imgCoord: rspCoords.바위,
        score: 0,
    }
    
    interval

    componentDidMount() { 
        this.interval = setInterval(this.changeHand, 100) 
    }

    componentDidUpdate() { // 리렌더링 후

    }

    

    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) => {
        clearInterval(this.interval)
        const {imgCoord} = this.state
        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} 0px` }} />
      <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 RPSClass
제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

뭔가 이상한데요.

https://github.com/ZeroCho/react-webgame/blob/master/5.%EA%B0%80%EC%9C%84%EB%B0%94%EC%9C%84%EB%B3%B4/RSPClass.jsx

제 강좌 코드로 했을 때 componentWillUnmount가 없어도 멈춰집니다.

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

애초에 componentWillUnmount는 실행도 되지 않으므로 여기 코드가 바뀐다고 해서 RSPClass 동작에 영향이 갈 수가 없습니다.

Bell Vise님의 프로필 이미지
Bell Vise
질문자

제로초님 코드로 해도 똑같네요. 제가 cra로 해서 그런걸까요. 일단 답변주셔서 고맙습니다.

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

cra면 스트릭트 컴포넌트 제거해보세요.

Bell Vise님의 프로필 이미지
Bell Vise
질문자

오 해결됐네요. 고맙습니다.

Bell Vise님의 프로필 이미지
Bell Vise

작성한 질문수

질문하기