개발노트

14 (2)context API 본문

React/basic

14 (2)context API

aloha2jh 2020. 7. 29. 21:59

클릭했을때 TD를 계산해서 열어주는 액션

불변성을 유지하기 위해 딱 그 줄을 복사해서 

그줄의 해당칸만 opened 로바꿔준다

 

Mine 컴포넌트에서 액션처리.

const reducer = (state,action)=>{  
    switch (action.type){
        
        case OPEN_TD: ///
            const tableData = [...state.tableData];
            tableData[action.trIndex] = [...state.tableData[action.trIndex]];
            tableData[action.trIndex][action.tdIndex] = TD_STATE.OPENED;
            return{
                ...state,
                tableData,
            } 
    }
}

 

Td컴포넌트에서 액션dispatch(발생) 지금클릭한 tr, td 인덱스를 넘겨준다.

const Td = ({trIndex, tdIndex}) =>{
  ...
    const onClickTd = useCallback(() =>{ 
        dispatch({ type:OPEN_TD, trIndex, tdIndex });
    },[]);

  ...
}
 

그러면  td 상태가 opend, 0으로 바뀌면서 스타일도 흰색으로 적용이 된다

 

 

칸들의 상태( 지뢰인지, 열린칸인지, 안열린그냥 칸인지)가 있고,

클릭시 상태에 따라 각각 다른 동작을 해줘야 되니까, 

switch문으로 만들어서 인자로 상태를 받는다.

        switch( tableData[trIndex][tdIndex] ){ //0, -1 ,-7 ... 

            case TD_STATE.NORMAL :  //그냥칸이면(-1) -열리게
                dispatch({ type:OPEN_TD, trIndex, tdIndex });
                return;
            case TD_STATE.MINE :  //마인칸이면(-7) -open_mine액션
                dispatch({ type:OPEN_MINE, trIndex, tdIndex });
                return;
            default : //이미열린칸, 깃발, 깃발-지뢰, 물음표, 물음표-지뢰 는-동작안하게
                return;

        }

 

 

 

오른쪽마우스 클릭 이벤트

우클릭 이벤트 잡아내기 위해 onContextMenu를 사용하면 된다

        <td onClick={onClickTd} onContextMenu={onClick_RightTd} 

(0) 브라우저기본메뉴안뜨게 e.preventDefault 부터 해줄것

    const onClick_RightTd =(e)=>{
    
        e.preventDefault(); //(0)
        
        switch( tableData[trIndex][tdIndex]  ){

            case TD_STATE.NORMAL :
            case TD_STATE.MINE :  // 지뢰, 기본칸이면 깃발로만들어줌.
                dispatch({ type:SET_FLAG, trIndex, tdIndex }); 
                return;
            case TD_STATE.FLAG_BUT:
            case TD_STATE.FLAG:
                dispatch({ type:SET_QUESTION, trIndex, tdIndex }); 
                return;
            case TD_STATE.QUESTION_BUT:
            case TD_STATE.QUESTION:
                dispatch({ type:SET_NORMAL, trIndex, tdIndex }); 
                return;
        }
    }

기본,지뢰 칸 -> 깃발

깃발,깃발지뢰 칸 -> 물음표

물음표,물음표지뢰 칸 -> 기본칸

 

(임의의 액션들을 만들었음. SET_QUESTION, SET_NORMAL, SET_FLAG, OPEN_MINE )

 

reducer로 액션 처리 

액션요청으로 TD_STATE상태값을 QUESTION으로 변경해주는 reducer.

        case SET_QUESTION:{
            const tableData = [...state.tableData];
            tableData[action.trIndex] = [...state.tableData[action.trIndex]];
            if( tableData[action.trIndex][action.tdIndex] === TD_STATE.MINE){ //지뢰칸이면
                tableData[action.trIndex][action.tdIndex] = TD_STATE.QUESTION_BUT; //지뢰플래그
            }else{
                tableData[action.trIndex][action.tdIndex] = TD_STATE.QUESTION; //그냥플래그
            }
            return{
                ...state,
                tableData,
            }
        }

우클릭을 했을때 지뢰칸이면 지뢰깃팔 칸인지, 그냥 깃발칸인지 구분해줘서 그렇지 간단한 코드

 

 

나머지 SET_NORMAL, SET_FLAG, OPEN_MINE도 동일

        case SET_NORMAL:{
            const tableData = [...state.tableData];
            tableData[action.trIndex] = [...state.tableData[action.trIndex]];
            if( tableData[action.trIndex][action.tdIndex] === TD_STATE.QUESTION_BUT){ //지뢰칸이면
                tableData[action.trIndex][action.tdIndex] = TD_STATE.MINE; //지뢰플래그
            }else{
                tableData[action.trIndex][action.tdIndex] = TD_STATE.NORMAL; //그냥플래그
            }
            return{
                ...state,
                tableData,
            }
        }
        case SET_FLAG:{
            const tableData = [...state.tableData];
            tableData[action.trIndex] = [...state.tableData[action.trIndex]];
            if( tableData[action.trIndex][action.tdIndex] === TD_STATE.MINE){ //지뢰칸이면
                tableData[action.trIndex][action.tdIndex] = TD_STATE.FLAG_BUT; //지뢰플래그
            }else{
                tableData[action.trIndex][action.tdIndex] = TD_STATE.FLAG; //그냥플래그
            }
            return{
                ...state,
                tableData,
            }
        }

 

 

 

OPEN_MINE의 경우 지뢰를 연것임으로 게임종료를 해줘야 되고,

export const TableContext = createContext({  
    tableData:[],
    dispatch: () => {},
    gameOver: true, //
});

const initialState = { //2
    tableData:[],
    timer:0,
    result:0,
    gameOver: true, //
}

gameOver: false 를 initialState와 context에도 새로 추가 한다

 

 

 

const Mine = () =>{
...
    const { timer , result , tableData, gameOver } = state; 
    const tblContextValue = useMemo( ()=>({ tableData, dispatch , gameOver }) ,[tableData]);
...
}

보내는 값에도 추가해준다.

 

 

지뢰클릭시 클릭안되게

그래서 Tr 컴포넌트에서 context에서 추가해준 gameOver값을 꺼내오고

onClickTd 칸 클릭이벤트때 gameOver T 면 return시킨다.

useCallback 을 사용했으니  (gameOver바뀌는 값이고) 의존성배열에도 추가해줘야 됨

const onClickTd = useCallback(() =>{ 
        if(gameOver){
            return;
        }
...
}

//우클릭 이벤트도 마찬가지
    const onClick_RightTd =(e)=>{
        e.preventDefault();
        if(gameOver){
            return;
        }
    ...
    }

 

초기값이 false니까, GAME_START액션 처리해주는 reducer에서 상태값 true로 꼭 바꿔준다~

 case START_GAME:
            return{
                ...state,
                tableData: plantMine(action.row, action.col, action.mine),
                gameOver: false,
            };

 

 

 

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

14. (4)context API  (0) 2020.07.31
14 (3)context API  (0) 2020.07.30
14. context API  (0) 2020.07.29
13. (3) useReducer  (0) 2020.07.29
13. (2) useReducer  (0) 2020.07.29