React

#13 useReducer

Sila 2022. 5. 1. 01:24

 

다음으로 useReducer에 대해 배워보자. useState와 비슷하게

 

현재 상태, 그리고 상태의 업데이트에 필요한 정보를 담은 action 값을 전달 받아 새로운 상태값을

 

return해주는 함수이다.

 

사용 방법도 비슷한데, useReducer는 상태를 바꿔주는 코드를 한 블럭에 몰아 넣고 이를 컴포넌트 밖으로

 

빼낼 수 있다는 것이 장점이다.

 

src 폴더에 useReduce 폴더를 만들고 Reduce.jsx 파일을 만든다.

 

/*  src/useReduce/Reduce.jsx  */

import react, { useReducer } from 'react'

const Reduce = () => {
    return(
        <>
            <h2> How to use Reducer </h2>
            <p>
                <button> show userid </button>
                <button> show userpw </button>
                <button> add list </button>
            </p>
            --------------------------------------
            <div>
                <li>
                    userid :
                </li>
                <li>
                    userpw :
                </li>
            </div>
            --------------------------------------
            <div></div>
        </>
    )
}

return default Reduce

 

우리는 버튼을 클릭하면 아래의 list에서 대응하는 값이 나타나도록 하고 싶다.

 

이런 state의 변화를 useReducer를 사용해 구현할 것이다.

 

Reduce 함수 안에 다음과 같이 useReducer 훅을 추가해주자.

 

/*  src/useReduce/Reduce.jsx  */

const Reduce = () => {
    const [state, dispatch] = useReducer(reducer, initalstate)
    
    ...후략    
}

괄호안의 인자들은 예전에 useState를 사용했을때 사용한 인자들과 거의 동일한 기능을 한다.

 

우리는 처음에 dispatch의 값을 바꿔 useReducer를 거쳐 reducer 함수 (좀 이따 만들거)

 

최종적으로 state를 바꿔준다.

 

useReducer의 첫 번째 인자는 우리가 state의 변화를 디자인하는 함수, 두 번째 인자는 초기 상태를 의미한다.

 

첫 번째 인자(함수)는 우리가 원하는대로 만들어주면 된다.

 

그런데 이 initialState, reducer함수는 컴포넌트 밖에, 심지어 다른 파일에도 나눠서 작성할 수 있다.

 

여기서는 같은 파일에 작성하되, 컴포넌트 외부에 작성한다.

 

/*  src/useReduce/Reduce.jsx  */

const initialState = {
    user: {
        userid:'userid',
        userpw:'userpw'
    },
    board: [
        { idx : 0, subject: 'qwerty', content: 'asdfgh', date : '2022-04-28' }
    ]
}

 

초기상태를 포함한 state의 data type은 굳이 객체가 아니라도 상관없다.

 

이제 reducer 함수를 작성한다.

 

/*  src/useReduce/Reduce.jsx  */

const reducer = (state, action) => {
    switch(action.type) {
        case 'SHOW_ID' :
            return {
                ...state,
                user: {
                    ...state.user,
                    userid:'qwerty123'
                }
            }
        
        case 'SHOW_PW' :
            return {
                ...state,
                user: {
                    ...state.user,
                    userpw:'asdfg456'
                }
            }
            
        case 'SHOW_LIST' :
            return {
                ...state,
                board : [
                    ...state.board,
                    {subject: 'qwerty2', content:'asdfgh2', date:'2022-04-28'}
                ]
            }
    }
    return state
}

 

reducer 함수는 state와 action을 매개변수로 받는다. state는 원래 상태이고, 우리가 조정해줄 것은 action이다.

 

함수를 보면 알 수 있듯 action의 값을 읽고 그 action에 대응하는 코드를 실행해

 

그 코드블럭 안의 내용을 기반으로 state값을 바꾼 후 return해준다.

 

이제 이 action 값들을 가져갈 함수, 그 함수를 가져갈 element들을 정해주면 된다.

 

Reduce 함수 컴포넌트 안에 다음과 같이 함수를 설정한다.

 

/*  src/useReduce/Reduce.jsx  */

const Reduce = () => {
    const [state, dispatch] = useReducer(reducer, initialState)
    
    const handleClick = () => {
        dispatch({type:'SHOW_ID'})
    }
    
    const handleClick2 = () => {
        dispatch({type:'SHOW_PW'})
    }
    
    const showList = () => {
        dispatch({type:'SHOW_LIST'})
    }
    
    const items = () => state.board.map((v) => {
        return (
            <ul key={v.idx}>
                <li>{v.subject}</li>
                <li>{v.content}</li>
                <li>{v.date}</li>
            </ul>
        )
    })
    
    return(
        <>
            <h2> How to use Reducer </h2>
            <p>
                <button onClick = {handleClick}> show userid </button>
                <button onClick = {handleClick2}> show userid </button>
                <button onClick = {showList}> show userid </button>
            </p>
            
            --------------------------------
            
            <div>
                <li>
                    userid: { state.user.userid }
                </li>
                <li>
                    userpw : { state.user.userpw }
                </li>
            </div>
            --------------------------------
            
            <div>{items()}</div>
        </>
    )
}

 

show userid 버튼을 누르면 handleClick 함수가 실행된다.

 

handleClick 함수는 disptach를 실행하는데, 이 안에 reducer 함수에 전해줄 action type이 있다.

 

handleClick 함수는 action.type = 'CHANGE_ID' 을 reducer 함수에 전달해

 

switch문에서 해당하는 action.type을 가진 조건문이 실행된다.

 

따라서 원래 state를 복사해 가져온 후, userid를 바꾼 후 return한다.

 

마지막으로 reducer 함수를 다른 파일로 분리해보자.

 

동일한 폴더에 reducer.jsx 폴더를 만들고 reducer 함수를 옮긴다.

 

/*  src/useReduce/reducer.jsx  */

const reducer (state, action) => {
    switch (action.type) {
        case 'CHANGE_ID' :
            return {
                ...state,
                user: {
                    ...state.user,
                    userid:'qwerty123'
                }
            }
        case 'CHANGE_PW' :
            return {
                ...state,
                user: {
                    ...state.user,
                    userpw:'asdfg456'
                }
            }
        case 'ADD_LIST' :
            return {
                ...state,
                board: [
                    ...state.board,
                    {idx:1, subject: 'qwerty2', content: 'asdfgh2', date:'2022-04-28'}
                ]
            }
    }
    return state
}

export default reducer

 

이걸 다시 Reduce.jsx로 import하면 된다.

 

/*  src/useReduce/Reduce.jsx  */

import react, {useReducer} from 'react'
import reducer from './reducer.jsx'

const initialState = {
    user: {
        userid:'userid',
        userpw:'userpw'
    },
    board: [
        {idx:0, subject: 'qwerty', content: 'asdfgh', date:'2022-04-28'}
    ]
}

const Reduce = () => {
    const [state, dispatch] = useReducer(reducer, initialState)

    const handleClick = () => {
        dispatch({type: 'CHANGE_ID'})
    }

    const handleClick2 = () => {
        dispatch({type: 'CHANGE_PW'})
    }

    const addList = () => {
        dispatch({type:'ADD_LIST'})
    }

    const items = () => state.board.map((v) => {
        return(
            <ul key={v.idx}>
                <li>{v.subject}</li>
                <li>{v.content}</li>
                <li>{v.date}</li>
            </ul>
        )
    })

    return (
        <>
            <h2> How to use Reducer </h2>

            <p>
                <button onClick = {handleClick}> show userid </button>
                <button onClick = {handleClick2}> show userpw </button>
                <button onClick = {addList}> add list </button> 
            </p>

            ---------------------------------------

            <div>
                <ul>
                    <li>
                        userid : {state.user.userid}
                    </li>
                    <li>
                        userpw : {state.user.userpw}
                    </li>             
                </ul>                
            </div>

            ---------------------------------------

            <div>{items()}</div>  
        </>
    )
}

export default Reduce

 

 

 

'React' 카테고리의 다른 글

#15 Redux part1  (0) 2022.05.07
#14 useMemo, useCallback  (0) 2022.05.02
#12 useContext  (0) 2022.04.29
#11 함수형 컴포넌트 2. useEffect  (0) 2022.04.29
#10 함수형 컴포넌트 1. intro, useState  (0) 2022.04.29