React - 가위바위보 예제로 알아보는 useEffect

Jenna·2023년 1월 4일
1

React

목록 보기
2/3
post-thumbnail

가위바위보 예제로 알아보는 useEffect 사용법

비동기처리를 공부할 때 가장 효과적인 가위바위보 예제로 useEffect의 쓰임을 학습한다.
class방식에서 쓰이는 componentDidMount, componentWillUnmount,componentDidUpdate 와 hooks에서 사용되는 useEffect를 비교하며 학습했다.


💫class로 가위바위보 구현하기


코드보기


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: '',
        imgCoord: '0',
        score: 0,
    };
    interval;
    //컴포넌트의 라이프사이클 
    componentDidMount() {
        //컴포넌트가 첫 랜더링 된 후 실행 -> 비동기 요청을 많이 함
        this.interval = setInterval(this.changeHand, 1000);
    }
    //componentDidUpdate() { //리랜더링 후 실행 
    //}
    componentWillUnmount() { //컴포넌트가 제거되기 직전에 실행 , 비동기 요청 정리 
        clearInterval(this.interval);
    }
    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, 1000);
        }, 2000);
    }
    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.바위,
            });
        }
    };
    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>
                <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>
            </>
        );
    }
}



클래스 라이프 사이클
constructor -> render -> ref -> componentDidMount -> (setState/props 바뀔때 -> shouldComponentUpdate(true) ->
render -> componentDidUpdate) -> 부모가 나를 없앴을 때 -> componentWillUnmount -> 소멸 의 라이프 사이클을 거친다.


✨ componentDidMount

컴포넌트가 첫 랜더링 된 후 실행되고 비동기 요청을 많이 한다.


✨ componentDidUpdate

컴포넌트가 리랜더링 후 실행된다.


✨ componentWillUnmount

컴포넌트가 제거되기 직전에 실행된다. 비동기 요청을 정리해줌


💫hooks로 가위바위보 구현하기


코드보기


import React, { useState, useRef, useEffect } 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];
};

const RSP = () => {
    const [result, setResult] = useState('');
    const [imgCoord, setImgCoord] = useState(rspCoords.바위);
    const [score, setScore] = useState(0);
    const interval = useRef();

    useEffect(() => { //componentDidMount,componentDidUpdate 역할 1대1대응은 아님
        interval.current = setInterval(changeHand, 100);
        return () => { //componentWillUnmount 역할 
            clearInterval(interval.current);
        }
    }, [imgCoord]);
    const changeHand = () => {
        if (imgCoord === rspCoords.바위) {
            setImgCoord(rspCoords.가위);
        } else if (imgCoord === rspCoords.가위) {
            setImgCoord(rspCoords.보);
        } else if (imgCoord === rspCoords.보) {
            setImgCoord(rspCoords.바위);
        }
    };
    const onClickBtn = (choice) => () => {

        clearInterval(interval.current);
        const myScore = scores[choice];
        const cpuScore = scores[computerChoice(imgCoord)];
        const diff = myScore - cpuScore;
        if (diff === 0) {
            setResult('비겼습니다.');
        } else if ([-1, 2].includes(diff)) {
            setResult('이겼습니다!');
            setScore((prevScore) => prevScore + 1);
        } else {
            setResult('졌습니다.')
            setScore((prevScore) => prevScore - 1);
        }
        setTimeout(() => {
            interval.current = setInterval(changeHand, 1000);
        }, 2000);
    };

    return (
        <>
            <div id="computer" style={{ background: `url(https://en.pimg.jp/023/182/267/1/23182267.jpg) ${imgCoord} 0` }}></div>
            <div>
                <button id="rock" className="btn" onClick={onClickBtn('바위')}>바위</button>
                <button id="scissor" className="btn" onClick={onClickBtn('가위')}>가위</button>
                <button id="paper" className="btn" onClick={onClickBtn('보')}>보</button>
            </div>
            <div>{result}</div>
            <div>현재 {score}점</div>
        </>
    );
}

✨ useEffect

componentDidMount,componentDidUpdate 역할 1대1대응은 아니다
컴포넌트가 랜더링 될 때마다 지정해준 작업을 실행시켜주는 역할을 한다.

profile
connecting the dots 💫

0개의 댓글