지뢰찾기 만들기(5)

20071 단어 ReactReact

Step 5

승리 조건 설정

const initialState = {
    tableData: [],
    timer: 0,
    result: '',
    halted: true,
    gameData: {
        row: 0,
        cell: 0,
        mine: 0,
    },
}

게임 데이터를 얻어오기 위한 게임 데이터 스테이트를 초기화해준다




case START_GAME:
            return {
                ...state,
                tableData: plantMine(action.row, action.cell, action.mine),
                halted: false,
                gameData: {
                    row: action.row,
                    cell: action.cell,
                    mine: action.mine,
                },
                timer: 0,
                result: '',
            };

게임이 시작하면 저렇게 초기화 시켜주고




OPEN_CELL 안에도

case OPEN_CELL: {
            ...

            let openCount = 0;
			
						...

openCount 변수를 만들어준다.




tableData안을 순회하며 0보다 큰값이 있으면

+1 씩 해주고

case OPEN_CELL: {
            ...

            checkAround(action.row, action.cell);
            
						tableData.forEach((tr,i)=>{
                tr.forEach((td,j)=>{
                    if (td >= 0) {
                        openCount += 1;
                    }
                })
            })

            let halted = false;
            let result = '';
            
            if (openCount === state.gameData.row*state.gameData.cell-state.gameData.mine) {
                halted = true;
                result = "Win!!";
            }   
            return {
                ...state,
                tableData,
                halted,
                result,
            }
            
        }

openCount 가 (행X열-지뢰개수)랑 같아지면 halted 체크하고 승리메세지를 작성한다.



그리고 저렇게 리턴해주면 끝




타이머 설정

useEffect 함수는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook 이다.

useEffect는 component가 mount 됐을 때, component가 unmount 됐을 때, component가 update 됐을 때,

특정 작업을 처리할 수 있다.

즉, 클래스형 컴포넌트에서 사용할 수 있었던 생명주기 메소드를 함수형 컴포넌트에서도 사용할 수 있게 된 것이다.



기본 형태 :

useEffect( function, deps )

  • function : 수행하고자 하는 작업
  • deps : 배열 형태이며, 배열 안에는 검사하고자 하는 특정 값 or 빈 배열 (dependency)



useEffect(() => {
    console.log('마운트 될 때만 실행된다');
  }, []);

컴포넌트가 화면에 가장 처음 렌더링 될 때 한 번만 실행하고 싶을 때는 deps 위치에 빈 배열을 넣는다.



useEffect(() => {
    console.log('렌더링 될 때 마다 실행된다');
  });

만약 배열을 생략한다면 리렌더링 될 때 마다 실행된다.



useEffect(() => {
    console.log(name);
    console.log('업데이트 될 때 실행된다');
  }, [name]);

특정값이 업데이트 될 때 실행하고 싶을 때는 deps 위치의 배열 안에 검사하고 싶은 값을 넣어준다.

(의존값이 들어있는 배열 deps 이라고도 한다. dependency를 의미.)

업데이트 될 때만 실행하는 것이 아니라 마운트 될 때도 실행된다.



useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  }, []);

cleanup 함수 반환 (return 뒤에 나오는 함수이며 useEffect에 대한 뒷정리 함수라고 한다.)

  • 언마운트 될 때만 cleanup 함수를 실행하고 싶을 때 → 두 번째 파라미터로 빈 배열을 넣는다.
  • 특정값이 업데이트 되기 직전에 cleanup 함수를 실행하고 싶을 때 → deps 배열 안에 검사하고 싶은 값을 넣어준다.




setInterval 함수

: 일정한 시간 간격으로 작업을 수행하기 위해서 사용합니다.clearInterval 함수를 사용하여 중지할 수 있습니다. 주의할 점은 일정한 시간 간격으로 실행되는 작업이 그 시간 간격보다 오래걸릴 경우 문제가 발생할 수 있습니다.

clearInterval()

이 실행중인 작업을 중지시키는 것은 아닙니다. 지정된 작업은 모두 실행되고 다음 작업 스케쥴이 중지 되는 것입니다.




이제 타이머를 구현해보자!


우선 액션을 만들어 주고

export const INCREMENT_TIMER = 'INCREMENT_TIMER';




리듀서에 액션을 추가해준다.

case INCREMENT_TIMER: {
            return {
                ...state,
                timer: state.timer + 1,
            }
        }




그리고

MineSearch 컴포넌트 안에 useEffect를 써서 타이머를 1초마다 디스패치 해준다.

useEffect(() => {
        const timer = setInterval(() => {
            dispatch({ type: INCREMENT_TIMER });
        }, 1000);
        return () => {
            clearInterval(timer);
        }
    },[]);

이러면 시간이 흘러가긴 하지만

우리는 시작 버튼을 눌렀을때 시간이 흐르게 하고싶다!



useEffect(() => {
        let timer;
        if (!halted){
            timer = setInterval(() => {
                dispatch({ type: INCREMENT_TIMER });
            }, 1000);
        }
        return () => {
            clearInterval(timer);
        }
    },[halted]);

중단이 안됐을 경우에만 디스패치를 한다 → 겜이 중단돼있으면 시간이 흐르지 않는다.




그리고 result 메세지도

result = `You won in ${state.timer} seconds!!`;

이렇게 바꿔주면

좋은 웹페이지 즐겨찾기