inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

웹 게임을 만들며 배우는 React

비동기 작업 해제에 대해

해결된 질문

335

Bell Vise

작성한 질문수 17

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로 해제가 안됩니다.

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

react

답변 1

0

제로초(조현영)

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

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

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

0

Bell Vise

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

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

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

 

0

제로초(조현영)

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

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

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

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

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

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

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

0

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

0

제로초(조현영)

뭔가 이상한데요.

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가 없어도 멈춰집니다.

0

제로초(조현영)

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

0

Bell Vise

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

1

제로초(조현영)

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

0

Bell Vise

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

npm run dev 실행 시 포트가 안뜨는 문제

0

211

2

timeouts.current를 useEffect 의 input값으로 넣었을때

0

89

2

렌더링 테스트 코드 (Hooks)

0

80

1

Cannot find package 'react-refesh' 이런 에러 뜨시는 분들 보세요.

0

154

1

해당 에러 뜨는 분들 보세요. "Uncaught TypeError: ReactDom.createRoot is not a function"

1

193

1

강사님 레포지토리에서 코드 복사 시 master 브랜치 말고 react18 브랜치꺼 복붙하세요ㅠㅠ

0

99

1

useMemo와 useCallback 사용 시기

0

208

2

onRightClickTd가 작동을 하지 않습니다.

0

228

1

action.type 불러오는 방식

0

222

2

onClickRedo 질문

0

172

1

const Try = require(./Try) 빨간줄

0

249

1

npx webpack 실행시

0

316

1

지뢰찾기 강좌에서 빈칸들 한번에 열기 파트에서 여쭤보고싶은부분이 있어서 글 올립니다.

0

236

1

강좌에서 다루지 않은 기능들은 어떻게 학습하면 좋을까요?

0

311

1

react devtool이 enable 않됩니다.

0

532

2

React 랜더링이 되지 않습니다.

0

414

2

비동기로 동작하는 setState에 대해서

0

332

1

npm run dev 할 때 에러발생

0

480

2

memo, PureComponenet, shouldComponentUpdate 관련 질문

0

207

1

devMiddleware의 필요성

0

353

1

리액트에서 화살표 함수를 사용해야하는 이유

0

937

2

path.join관련질문

0

283

2

2-9. 웹팩 데브 서버와 핫 리로딩 설치과정 시 에러

0

376

1

next.js 에서 이와 비슷한 예제를 돌리고있는데 react랑 달라서 질문 드립니

1

494

4