Front/React

useReducer - React 배우기

oodada 2024. 3. 19. 09:47
반응형

useReducer

useReducer 란?

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

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

useReducer 사용법

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

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

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

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,
    })

    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',
    })

    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/components/App.js
import React, { useReducer } from 'react'
import TodoHd from './TodoHd'
import TodoEditor from './TodoEditor'
import TodoList from './TodoList'

const mockTodo = [
    {
        id: 1,
        isDone: false,
        task: '고양이 밥주기',
        createdDate: new Date().getTime(),
    },
    {
        id: 2,
        isDone: false,
        task: '감자 캐기',
        createdDate: new Date().getTime(),
    },
    {
        id: 3,
        isDone: false,
        task: '고양이 놀아주기',
        createdDate: new Date().getTime(),
    },
]

// reducer 함수로 상태를 변경합니다.
// state : 현재 상태
// action : 상태를 변경할 때 참조하는 값
function reducer(state, action) {
    switch (action.type) {
        case 'ADD':
            return [action.payload, ...state]
        case 'UPDATE':
            return state.map((it) => (it.id === action.payload ? { ...it, isDone: !it.isDone } : it))
        case 'DELETE':
            return state.filter((it) => it.id !== action.payload)
        default:
            return state
    }
}

function App() {
    // useReducer를 이용하여 상태를 관리합니다.
    // 첫 번째 인수로 reducer 함수를, 두 번째 인수로 초기 상태를 전달합니다.
    // 반환값으로 state와 dispatch 함수를 받습니다.
    // state : 현재 상태
    // dispatch : action을 발생시키는 함수
    // dispatch 함수를 이용하여 action을 발생시키면 reducer 함수가 호출됩니다.
    // reducer 함수가 호출되면 state가 변경됩니다.
    // state가 변경되면 컴포넌트가 리렌더링됩니다.
    const [todo, dispatch] = useReducer(reducer, mockTodo)

    const addTodo = (task) => {
        const newTodo = {
            id: Date.now(),
            isDone: false,
            task,
            createdDate: new Date().getTime(),
        }
        dispatch({ type: 'ADD', payload: newTodo })
    }

    const onUpdate = (id) => {
        dispatch({ type: 'UPDATE', payload: id })
    }

    const onDelete = (id) => {
        dispatch({ type: 'DELETE', payload: id })
    }

    return (
        <div>
            <TodoHd />
            <TodoEditor addTodo={addTodo} />
            <TodoList todo={todo} onUpdate={onUpdate} onDelete={onDelete} />
        </div>
    )
}

export default App
반응형
티스토리 친구하기