Front/React

[Hooks] useReducer - React 배우기

oodada 2024. 3. 19. 09:47

useReducer

useReducer 란?

useReduceruseState 보다 더 다양한 컴포넌트 상태를 관리하는 Hook 입니다. useState 는 컴포넌트 상태를 관리하는 가장 기본적인 Hook 이지만, useReducer 는 복잡한 상태 로직을 다루기에 더 적합합니다.

컴포넌트에서 상태 변화 코드를 쉽게 분리할 수 있고, 상태 로직을 컴포넌트 바깥으로 빼내어 재사용할 수 있습니다.

useReducer 사용법

useReducer 는 다음과 같이 사용합니다.

- 타입 정의

const ACTION_TYPE1 = 'ACTION_TYPE1'
const ACTION_TYPE2 = 'ACTION_TYPE2'

- reducer 함수 정의

const [state, dispatch] = useReducer(reducer, initialState)
  • state : 현재 상태
  • dispatch : 액션을 발생시키는 함수, 액션을 발생시키면 리듀서 함수가 호출되어 상태가 변경됩니다.
  • reducer : 상태를 변경하는 함수
  • initialState : 초기 상태

reducer 함수는 다음과 같이 작성합니다.

reducer 함수는 현재 상태와 액션을 받아서 새로운 상태를 반환합니다.
action.type 은 대문자로 작성하여 액션 타입이 상수임을 나타냅니다.

function reducer(state, action) {
    switch (action.type) {
        case 'ACTION_TYPE1':
            return { ...state, ...action.payload }
        case 'ACTION_TYPE2':
            return { ...state, ...action.payload }
        default:
            return state
    }
}

useReducer 예제

- useStaet 사용

useState 를 사용하여 컴포넌트 상태를 관리하는 예제로 상태관리가 복잡해질수록 코드가 복잡해 관리가 어려워집니다.
또한 상태를 변경하는 로직이 컴포넌트 안에 선언되어 있어 재사용이 어렵습니다.

import React, { useState } from 'react'

function Counter() {
    const [count, setCount] = useState(0)

    const onIncrease = () => {
        setCount(count + 1)
    }

    const onDecrease = () => {
        setCount(count - 1)
    }

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={onIncrease}>+1</button>
            <button onClick={onDecrease}>-1</button>
        </div>
    )
}

export default Counter

- useReducer 사용

useReducer 를 사용하여 컴포넌트 상태를 관리하는 예제로 상태관리가 복잡해져도 코드가 간결해집니다.
또한 상태를 변경하는 로직이 컴포넌트 바깥에 선언되어 있어 재사용이 용이합니다.

dispatch 함수를 이용하여 액션을 발생시키면 reducer 함수가 호출되어 상태가 변경됩니다. 상태가 변경되면 컴포넌트가 리렌더링됩니다.

쉽게 말해, dispatch가 파견 나간 직원이라 생각하고, reducer가 파견 받은 회사라 생각하면 이해하기 쉽습니다. 파견 나간 직원이 정보를 보내면 파견 받은 회사에서 정보를 처리하고, 결과를 돌려줍니다.

// src/components/Counter.js
import React, { useReducer } from 'react'

// reducer 함수로 상태를 변경
// state : 현재 상태
// action : 상태를 변경할 때 참조하는 값
function reducer(state, action) {
    switch (action.type) {
        case 'INCREMENT':
            return { counter: state.counter + 1 }
        case 'DECREMENT':
            return { counter: state.counter - 1 }
        case 'RESET':
            return { counter: 0 }
        default:
            return state
    }
}

function Counter() {
    // useReducer 로 상태 관리
    // state : 현재 상태
    // dispatch : 액션을 발생시키는 함수
    // reducer : 상태를 변경하는 함수
    // initialState : 초기 상태
    const [state, dispatch] = useReducer(reducer, {
        counter: 0,
    })

    // state : { counter: 0 }
    return (
        <div>
            <h1>Counter</h1>
            <p>Current count: {state.counter}</p>
            <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
            <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
            <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
        </div>
    )
}

export default Counter

useReducer 여러 상태 사용

useReducer 를 사용하여 여러 상태를 관리할 수 있습니다.

import React, { useReducer } from 'react'

function reducer(state, action) {
    switch (action.type) {
        case 'INCREMENT':
            return { ...state, counter: state.counter + 1 }
        case 'DECREMENT':
            return { ...state, counter: state.counter - 1 }
        case 'RESET':
            return { ...state, counter: 0 }
        default:
            return state
    }
}

function Counter() {
    const [state, dispatch] = useReducer(reducer, {
        counter: 0,
        name: 'counter',
    })
    // state : { counter: 0, name: 'counter' }

    return (
        <div>
            <h1>
                {state.name}: {state.counter}
            </h1>
            <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
            <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
            <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
        </div>
    )
}

export default Counter

상태 로직 분리

useReducer 를 사용하여 상태 로직을 분리하면 컴포넌트 코드가 간결해지고, 상태 로직을 재사용할 수 있습니다.

// src/reducers/counterReducer.js
export const ACTION_TYPE = {
    INCREMENT: 'INCREMENT',
    DECREMENT: 'DECREMENT',
    RESET: 'RESET',
}

export function counterReducer(state, action) {
    switch (action.type) {
        case ACTION_TYPE.INCREMENT:
            return { ...state, counter: state.counter + 1 }
        case ACTION_TYPE.DECREMENT:
            return { ...state, counter: state.counter - 1 }
        case ACTION_TYPE.RESET:
            return { ...state, counter: 0 }
        default:
            return state
    }
}
// src/components/Counter.js
import React, { useReducer } from 'react'
import { counterReducer, ACTION_TYPE } from '../reducers/counterReducer'

function Counter() {
    const [state, dispatch] = useReducer(counterReducer, {
        counter: 0,
        name: 'counter',
    })

    return (
        <div>
            <h1>
                {state.name}: {state.counter}
            </h1>
            <button onClick={() => dispatch({ type: ACTION_TYPE.INCREMENT })}>+1</button>
            <button onClick={() => dispatch({ type: ACTION_TYPE.DECREMENT })}>-1</button>
            <button onClick={() => dispatch({ type: ACTION_TYPE.RESET })}>Reset</button>
        </div>
    )
}

export default Counter

useReducer vs useState

useReduceruseState 는 상태를 관리하는 두 가지 방법입니다.

useState 는 간단한 상태 관리에 적합하고, useReducer 는 복잡한 상태 관리에 적합합니다.

useState 는 상태를 변경하는 로직이 컴포넌트 안에 선언되어 있어 재사용이 어렵고, 상태 관리가 복잡해질수록 코드가 복잡해 관리가 어려워집니다.

useReducer 는 상태를 변경하는 로직을 컴포넌트 바깥에 선언하여 재사용이 용이하고, 상태 관리가 복잡해져도 코드가 간결해집니다.

todolist를 useReducer로 변경하기

todo list

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

리액트(React.js) 커리큘럼  (0) 2024.03.24
[Hooks] useContext - React 배우기  (0) 2024.03.20
최적화 - React 배우기  (0) 2024.03.18
React를 이용한 todo list app 만들기  (0) 2024.03.14
useEffect, 생명주기 - React 배우기  (0) 2024.03.11
티스토리 친구하기