개발노트

13. useReducer 본문

React/basic

13. useReducer

aloha2jh 2020. 7. 28. 21:39

틱택토(삼목게임) 만들기

 

TicTacToe > Table > Tr > Td

const Tictactoe = () =>{
   const [winner, setWinner] = useState('');
   const [turn, setTurn] = useState('o');
   const [tableData, setTableData] = useState([ ['','',''],['','',''],['','',''] ]);
}

실제 이벤트 발생하는 곳이  Td컴포넌트 인데, tictactoe 에서 state들을 td로 보내려면

두번이나 거쳐서 Td로 가는 문제점이발생 

 

 


state 갯수를 줄일수 있는 useReducer

const [state, dispatch] = useReducer( reducer, initialState );

useReducer를 불러오고

 

    const [state, dispatch] = useReducer( reducer, initialState );

    //(1) state들
    const initialState = {
        winner: '',
        turn :'o',
        tabledate: [ ['','',''],['','',''],['','',''] ]
    }
      
    // const [winner, setWinner] = useState('');
    // const [turn, setTurn] = useState('o');
    // const [tableData, setTableData] = useState([ ['','',''],['','',''],['','',''] ]);
    
    //(2) state들을 어떻게 바꿀지.
    const reducer = (state, action) =>{
        
    }

(1) initialState :  필요한 state담는다.

state 에서 initialState를만들었기 때문에, initialState에 정의해놓은 winner를 state.winner로 접근이가능

state = useReducer( reducer, initialState );

dispatch = useReducer( reducer, initialState );랑 같으니까?

 

(2) reducer : reducer함수에  state들을 어떻게 바꿀지 정의.

 

 

(3) dispatch ({ /*action*/ }) :  action 실행

 

ex)만약 winner를 o로 바꾸려면? 

    dispatch ({  /*action*/  type:'SET_WINNER', winner:'o' })

타입이름과 이름을 적어서 액션객체를만들어준다. 

이액션 객체를 dispatch로 실행하는것.

 

액션으로 이렇게 원하는 state를 적어줬다고 해서 자동으로 state가 바뀌지 않음

action을 해석해서 state를 바꿔주는게 reducer.

 

action이 dispatch(실행)될때마다,  reducer함수가 실행되는것!

 

 

    //state들을 어떻게 바꿀지.
    const reducer = (state, action) =>{
        switch( action.type ){
            case 'SET_WINNER' :
                return{
                    ...state,
                    winner:action.winner
                }
        }
    }



    const onClickTable = useCallBack ( ()=>{
        //table클릭시 winner를 o로 바꾼다
        dispatch ({  /*action*/  type:'SET_WINNER', winner:'o' })

    },[])

그런데  action은 여러개고, 그때마다 reducer함수가 실행됨.

그래서 reducer함수 에서 어떤action인지 알아내야 되서 action.type을 써서 구분.

state.winner = action.winner이런식으로 바꾸면안된다는점

 

 

 

import React , { useState ,  useReducer , useCallback } from 'react';
import Table from './Table'; 
 
const initialState = {
    winner: '',
    turn :'o',
    tabledate: [ ['','',''],['','',''],['','',''] ]
}
 //state들을 어떻게 바꿀지.
const reducer = (state, action) =>{
    switch( action.type ){
        case 'SET_WINNER' :
            return{
                ...state,
                winner:action.winner
            }
    }
}

const Tictactoe = () =>{ 
    const [state, dispatch] = useReducer( reducer, initialState );
 
    const onClickTable = useCallback ( ()=>{
        //table클릭시 winner를 o로 바꾼다
        dispatch ({  /*action*/  type:'SET_WINNER', winner:'o' })

    },[]);
    
    return (
        <>
            <Table onClickTableEvent={onClickTable} />
            {state.winner && <p>{state.winner} 님의 승리</p> }
        </>
    ) 
}
 
export default Tictactoe;

자식에게 onClick으로 ..  onClickTable함수를 넘겨줬고

 

import React from 'react';
import Tr from './Tr';

const Table = ( {onClickTableEvent} )=>{
    return(
        <> 
        <table onClick={onClickTableEvent}>
            <tbody>
            <Tr>{''}</Tr>
            </tbody>
        </table></>
    )
}

export default Table;

onClickTableEvent으로넘겨줬으니까 onClickTableEvent으로받야아 한다 **(또르륵..)

 

 

그리고 action.type은 변수로 빼준다

대문자로써주는게 코딩컴벤션.

 

배열로 tr, td컴포넌트 만들기

Tictactoe에 있는 initialState 에 선언해 놓은 2차원 배열 값들( [ ['','',''],['','',''],['','',''] ] )을 이제

[] [] [] 이걸 tr컴포넌트, 안에있는3개 를 td컴포넌트 로 만든다.

 

(1)Tictactoe에서 Table에게

tableData를 props으로 넘겨줌.

 <Table onClickTableEvent={onClickTable} 
                    tableData={state.tableData} />

 

(2)table에서 tableData props를 받아서

요소가 3개인 배열을 만들고

Array(3)

{Array(tableData.length).fill() }   <Tr />

map 반복문으로 [ [],[],[] ] [] 를 tr로 받아서

갯수만큼 자식 컴포넌트를 만든다

{ Array(tableData.length).fill().map( ( tr )=>( <Tr /> ) ) }

 

(3) table -> Tr에게 각 [] 하나씩 넘겨줌.

{ Array(tableData.length).fill().map( ( tr )=>( <Tr /> ) ) }
{ Array(tableData.length).fill().map( ( tr ,i )=>( <Tr trData={ tableData[i] }	/> ) ) }

 

(4) Tr 에서 trData props를 받아서

td를 3개 만든다. 

<tr><Td /></tr>
 <tr>
 { Array(trData.length).fill().map(( td )=>( <Td /> ) )}
 </tr>

셀 하나하나가 다 컴포넌트 !

 

 

 

 

 

 

 

//Tictactoe.jsx
import React , { useState ,  useReducer , useCallback } from 'react';
import Table from './Table'; 
 
const initialState = {
    winner: '',
    turn :'o',
    tabledate: [ ['','',''],['','',''],['','',''] ]
}

const SET_WINNER = 'SET_WINNER';

 //state들을 어떻게 바꿀지.
const reducer = (state, action) =>{
    switch( action.type ){
        case SET_WINNER :
            return{
                ...state,
                winner:action.winner
            }
    }
}

const Tictactoe = () =>{ 
    const [state, dispatch] = useReducer( reducer, initialState );
 
    const onClickTable = useCallback ( ()=>{
        //table클릭시 winner를 o로 바꾼다
        //dispatch ({  /*action*/  type: SET_WINNER, winner:'o' })

    },[]);
    
    return (
        <>
            <Table onClickTableEvent={onClickTable} 
                    tableData={state.tabledate} 
            />
            {state.winner && <p>{state.winner} 님의 승리</p> }
        </>
    ) 
}
 
export default Tictactoe;
// Table.jsx
import React from 'react';
import Tr from './Tr';

const Table = ( {onClickTableEvent, tableData } )=>{
    return(
        <> 
        <table onClick={onClickTableEvent}>
            <tbody>
            { Array(tableData.length).fill().map( ( tr ,i)=>( <Tr trData={ tableData[i] }/> ) ) }
            </tbody>
        </table></>
    )
}

export default Table;
//Tr.jsx
import React from 'react';
import Td from './Td';

const Tr = ({trData}) =>{
    return(
        <tr>
        { Array(trData.length).fill().map(( td )=>( <Td /> ) )}
        </tr>
    )
}

export default Tr;
//Td.jsx
import React from 'react';

const Td = ()=>{
    return(
        <td></td>
    )
}

export default Td;

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

13. (3) useReducer  (0) 2020.07.29
13. (2) useReducer  (0) 2020.07.29
12. hooks / useEffect , useMemo  (0) 2020.07.28
12. componentDidUpdate , setInterval  (0) 2020.07.27
11 (2)hooks / useEffect  (0) 2020.07.26