본문 바로가기

React + React Native + Expo

[React 연습 5일차] 리액트 TicTacToe Game 구현 with Hooks API

반응형

 

 

오늘 수업시간에 한 틱택토 게임 함수형 Hooks API 써서 만들기 연습 ! 

useReducer 함수를 따로 빼는 것과 useEffect 부분 이 아직 안익숙하다. 일단 연습은 계속 해보기 ! 

 

오늘 처음 본(?)

useEffect 

useEffect(()=>{}) 을 사용해서 리액트에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지 말함. 리액트는 우리가 넘긴 함수를 기억했다가 (요 함수가 'effect'라고 불림) DOM 업데이트 수행 수 불러낸다. 

useEffect를 꼭 컴포넌트 안에서 불러내는 이유는 ? -> 내부 state 상태 변수들, props 들에게 접근할 수 있게 된다. 함수 범위 안에 있어서 API 없이 값을 얻을 수 있기 때문 ! 

 

useEffect는 최초 렌더링에 실행되고 이후 모든 업데이트에서 수행된다. 만약 특정 기준을 만들고 싶으면

useEffect( 첫 번째 인자 : 함수 ()=>{} , ___두 번재 인자 [] ___) 에 기준이되는 상태값을 넣어주면 된다. 오늘 연습할 때 요 두 번째 인자는 state.xIsNext 로 false < -> true 클릭 눌릴 때마다 바뀌었는데 변화가 있을 때마다 useEffect안의 코드가 실행되었다. 

 

<오늘 useEffect 사용한 부분 > 

const defaultState={
    squares:Array(9).fill(null),
    xIsNext:false,
    winner:null,
}

const Game = () => {

    const [state,dispatch] =React.useReducer(reducer, defaultState)

    const handleClick=(n)=>{
        if(state.squares[n]) return;
        if(state.winner) return;
        dispatch({type:'NEXT', index:n})
    }

    React.useEffect(()=>{
        let win = Winner(state.squares)
        console.log(win)
        if(win){
            console.log(win)
            dispatch({type:'win', winner:win})
        }
    },[state.xIsNext])

useEffect는 const Game component 안에 있다. 실행 코드들 중 상태인 squares에 접근하고 있다 요 부분떄문에 useEffect는 컴포넌트 안에 넣기 ! 그리고 두 번째 인자가 state.xIsNext로 또한 상태값 에 바로 접근하고 있다. 

 

 

 

 


 

 

 

App.jsx

import React,{Component} from 'react';
import Game from './components/game/Game'

const App=()=>{
    
    return(
        <>
            <Game/>
        </>
    )
    
}

export default App

Game.jsx

import React from 'react'
import Board from './Board'
import Styled from 'styled-components'

const BoardDiv = Styled.div`
    display:flex;
    flex-wrap:wrap;
    align-item:center;
    justify-content:center;
    width:300px;
`

const Winner =(squares)=>{
    let lines =[
        [0,1,2],
        [3,4,5],
        [6,7,8],
        [0,3,6],
        [1,4,7],
        [2,5,8],
        [0,4,8],
        [2,4,6]
    ]
    for (let i=0; i<lines.length; i++){
        let [a,b,c] = lines[i]
        if(squares[a] && squares[a] === squares[b] && squares[a]===squares[c]){
            return squares[a]
        }
    }
    return false
}

const reducer=(state,action)=>{
    switch(action.type){
        case 'NEXT':
            let {squares} = {...state}
            squares[action.index] = state.xIsNext ? 'X':'O'
            return{
                ...state,
                xIsNext:!state.xIsNext,
                squares,
            }
        case 'win':
            return{
                ...state,
                winner : action.winner
            }
    }
}

const defaultState={
    squares:Array(9).fill(null),
    xIsNext:false,
    winner:null,
}

const Game = () => {

    const [state,dispatch] =React.useReducer(reducer, defaultState)

    const handleClick=(n)=>{
        if(state.squares[n]) return;
        if(state.winner) return;
        dispatch({type:'NEXT', index:n})
    }

    React.useEffect(()=>{
        let win = Winner(state.squares)
        console.log(win)
        if(win){
            console.log(win)
            dispatch({type:'win', winner:win})
        }
    },[state.xIsNext])

    return(
        <> 
            {state.winner ? `${state.winner}님 승리!` : `Next player is ${state.xIsNext ? 'X' :'O' }`}
            <BoardDiv>
                <Board onClick={handleClick} squares = {state.squares}/>
            </BoardDiv>
        </>
    )
}

export default Game

Board.jsx

import React from 'react'
import Square from './Square'

const Board =({onClick, squares})=>{
    const square = squares.map((v,i)=>{
        return(
            <>
                <Square onClick={()=>onClick(i)} key={i} value={v}/>
            </>
        )
    })

    return square

}

export default Board

Square.jsx

import React from 'react'
import Styled from 'styled-components'

const Button = Styled.button`
    width:33.333%;
    height:70px;
    border:1px solid #000;
    background:#fff;
    cursor:pointer;
    font-size:30px;
`

const Square =({onClick, value})=>{
    return(
        <>
            <Button onClick={()=>onClick()}>{value}</Button>
        </>
    )
}

export default Square

 

 

 

반응형