개발노트

11 (2)hooks / useEffect 본문

React/basic

11 (2)hooks / useEffect

aloha2jh 2020. 7. 26. 21:45

우선 훅스에는 라이프사이클없으니까 제외한 나머지를 훅스로 변경

import React, { useState , useRef  } from 'react';

const rpsCoords = {
    rock:'0px',
    scissor: '-142px',
    paper: '-284px',
};

const score = {
    scissor: 1, //가위
    rock:0,     //바위
    paper:-1    //보
}

//컴퓨터가 어떤손 내는지 판단
const computerChoice = (imgLocation)=>{
    return Object.entries(rpsCoords).find( function(v){ 
        return v[1] === imgLocation; 
    })[0];
}
 
const RPS =()=> {

    const [ result, setResult ] = useState('');
    const [ imgLocation, setImgLocation] = useState(0);
    const [ score, setScore ] = useState(0);
    const interval = useRef();

    const interval;

    // componentDidMount(){ //첫렌더링 된후
    //     //이미지 위치값을 묵 으로
    //     //인터발을 걸어주는데 안에 화살표함수에서 img위치가 rsp위치의 묵과 같다면
    //     // 상태값의 이미지위치를 가위로


    //     this.setState( {imgLocation: rpsCoords.rock }); 
    //     this.changeHand();

    // }
    // componentWillUnmount(){ // 제거직전

    // }

    // componentDidUpdate(){ //리렌더링된후 실행

    // }
 

    const  changeHand = ()=>{
        interval.current = setInterval( ()=>{  
            if( imgLocation == rpsCoords.rock ){
                setImgLocation(rpsCoords.scissor);
            }else if( imgLocation == rpsCoords.scissor ){
                setImgLocation(rpsCoords.scissor);
            }else{
                setImgLocation(rpsCoords.rock);
            }
        }, 500 );
        
    }

    //사용자가 가위바위보 선택했을때
    const onClickBtn = ( userChoose )=>{
        clearInterval( this.interval );
 
        const userScore = score[userChoose]; //siccer 1 
        const comScore = score[computerChoice(imgLocation)];  //paper -1
  
        const diff = userScore - comScore; //결과

        if(diff === 0){ // 
            setResult('again')
        }else if( [-1, 2].includes(diff) ){ //이겼음
            
            setResult( 'win!');
            setScore( ( prevScore )=>{ return[...prevScore, +1 ] } );
             
        }else{  //졌다
            
            setResult('lose');
            setScore( ( prevScore )=>{ return[...prevScore, -1 ] } );
 
        }
        clearInterval(this.interval); 
        setTimeout( ( )=>{ this.changeHand() }, 2000 );
    }

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

export default RPS;

 

 

 

 

 

 

class component는 컴포넌트 생성업데이트소멸 에 따라 이벤트가 있는것처럼

Hook에서의 useEffect 

 

-컴포넌트가 처음 화면에 나타나게 될때, 화면에서사라지게 될때 이벤트를 걸 수 있다

-props나 state가 update 되기 전, 될때 도 이벤트를 걸 수 있다

-리렌더링 될때마다 이벤트를 걸 수도 있다.

 

useEffect( ()=>{ '하고자하는작업' } , [  dependency.. 배열  ] ) 

 

 

 

 

 

 

 

테스트해본결과

배열(의존값)이 없을경우엔,

처음 렌더링될때 컴포넌트가 그려지는 갯수만큼 실행이 됨.

 

그리고 return안은 만약 componentDidMount 때 인스턴스생성을 해줬다면

componentWillUnmount 때 처럼 인스턴스 제거를 해주는 역할.

컴포넌트 remove했을때 발생.

useEffect ( ()=>{ //componentDidMount 
  //첫렌더링된후, 컴포넌트가그려질때 발생
  console.log('컴포넌트 갯수만큼 그려질때마다, 실행'); 
  	//인스턴스생성
  
  return()=>{  //componentWillUnmount  
  //컴포넌트가 화면에서 사라질때. 발생 
     console.log('unmount');
    //인스턴스제거
  } 
},[])

 

 

 

 

 

 

 

 

 

배열에 등록할 경우

useEffect ( ()=>{ //componentDidMount , componentDidUpdate

  //첫렌더링된후, 컴포넌트가그려질때 발생
  console.log('A : 컴포넌트 처음 그려질때, 업데이트 되서 그려질때'); 
  	
  
  return()=>{  // componentDidUpdate 
  //컴포넌트의 props, state가 업데이트 될때 발생
     console.log(' B : before update .. state ');
    
  } 
},[ props, state ])

배열 값이(상태가) 바뀔때마다 호출이 됨.

배열안의 의존값이(state또는 props)가 들어가면 componentDidUpdate역할에 좀더 가까워 지는것 같다.

return() 이 실행되서 update전에 호출이 된다음

상태가 바뀌고 A가 실행됨.

state바뀔때 hook함수 전체가 재 실행되기 때문에

업데이트하고 그려주고 해서 B , A 가 발생

 

 

 

 

 

 

 

 

배열[] 의존성등록을 해주지 않을 경우

 useEffect ( ()=>{ //componentDidMount, componentDidUpdate 역할

        //첫렌더링된후  
        console.log( ' 1 :Start');
        changeHand(); 

        return()=>{ //componentWillUnmount 

            console.log('2 :End');
             clearInterval(  interval.current ); //////
        } 
    },[   ])

    const changeHand = ()=>{
        
        interval.current = setInterval( ()=>{ 
            console.log("imgLocation:"+imgLocation); 
            if( imgLocation == rpsCoords.rock ){
                console.log('rock'); 
                setImgLocation(rpsCoords.scissor);
            }else if( imgLocation == rpsCoords.scissor ){
                console.log('scissor');
                setImgLocation(rpsCoords.paper);
            }else{
                console.log('paper');
                setImgLocation(rpsCoords.rock);
            }
        }, 2000 );
        
    }

실행할때 render일어나서 화면변한다음,

그다음부턴 렌더링일어나지 않고,

내부적으로만 setInterval이 실행되는데,

상태값을 변경해주지 않음...

 

 useEffect ( ()=>{ //componentDidMount, componentDidUpdate 역할

        //첫렌더링된후  
        console.log( ' 1 :Start');
        changeHand(); 

        return()=>{ //componentWillUnmount 

            console.log('2 :End');
             clearInterval(  interval.current ); //////
        } 
    },[  imgLocation ])

    const changeHand = ()=>{
        
        interval.current = setInterval( ()=>{ 
            console.log("imgLocation:"+imgLocation); 
            if( imgLocation == rpsCoords.rock ){
                console.log('rock'); 
                setImgLocation(rpsCoords.scissor);
            }else if( imgLocation == rpsCoords.scissor ){
                console.log('scissor');
                setImgLocation(rpsCoords.paper);
            }else{
                console.log('paper');
                setImgLocation(rpsCoords.rock);
            }
        }, 2000 );
        
    }

의존성값이 없을경우, setImgLocation 부분이 실행이 되지 않아서

state 즉 바꿔주는부분 []의존성배열에 추가해야 정상적으로 작동.

 

 

추가후

변경하고싶은 상태값의 경우 의존성배열에 꼭 넣어줘야 상태값이 바뀐다는점.

화면 렌더링도 의존성배열에 있어야 바뀌줌

 

 

 

 

 

 

 

 

 

useEffect를 여러개 쓸 수도 있다.

   useEffect ( ()=>{   
    },[  imgLocation ]);
 
    useEffect ( ()=>{   
    },[  rpsCoords ])

    useEffect ( ()=>{   
    },[   ])

 

 

 

 

 

 

 

-hooks는 부모컴포넌트 변경시 자식컴포넌트도 무조건 변경됨

그래서 리렌더링 안되게 하려면 memo로 감싸준다.

 

-hooks는 useState같은 리액트패키지를 써야 훅스고

안쓰면 그건 그냥 함수형 컴포넌트

 

 

<html lang="ko">
    <head>
        <meta charset="utf-8">
        <title>game</title>
    </head>
    <style>
        #computer {
            width: 142px;
            height: 200px;
            background-position: 0 0;
            outline: 5px solid gold;
        }
        ul{width:100%; padding:0; height:180px;}
        li{ width: 142px; height:180px; outline:1px solid grey; float:left; list-style:none; } 
        li{
            background: url(https://en.pimg.jp/023/182/267/1/23182267.jpg)  0px -11px;
        }
        li#scissor{
            background-position: -142px -11px;
        }
        li#paper{
            background-position: -284px -11px;
        }
    </style>
    <body>
        <div id="root"></div>
        <script src="./dist/app.js"> 
        </script>
    </body>
</html>

'React > basic' 카테고리의 다른 글

12. hooks / useEffect , useMemo  (0) 2020.07.28
12. componentDidUpdate , setInterval  (0) 2020.07.27
11. react life cycle  (0) 2020.07.26
10. (4)jsx 에서 for, if  (0) 2020.07.26
10. (3) hooks / useState  (0) 2020.07.26