ReactJS - useReducer 사용법

안녕하세요, 프로그래밍에 도전하는 여러분! 오늘 우리는 React hooks의 세계로 흥미로운 여정을 떠납니다. 특히 강력한 useReducer hook에 집중해보겠습니다. 프로그래밍 초보자라도 걱정하지 마세요. 저는 수년 동안 수많은 학생들을 가르치며 이 단계별로 안내해왔습니다. 시작해보겠습니다!

ReactJS - Using useReducer

useReducer는 무엇인가요?

자세한 내용에 들어가기 전에 useReducer에 대해 이해해보겠습니다. 마치 비디오 게임을 플레이할 때, 캐릭터가 다양한 상태를 가지고 있다고 상상해보세요 - 체력, 힘, 속도 등. 게임을 진행하면서 이 상태들이 행동에 따라 변합니다. useReducer는 이러한 상태 변화를 특정 규칙에 따라 관리하는 게임 엔진과 같습니다.

React 용어로는, useReducer는 우리의 애플리케이션에서 복잡한 상태 로직을 관리하는 데 도움을 주는 hook입니다. 상태에 여러 서브 값이 있거나, 다음 상태가 이전 상태에 따라 달라질 때 특히 유용합니다.

useReducer hook의 서명

이제 useReducer를 코드에서 어떻게 사용하는지 살펴보겠습니다. 기본 구조는 다음과 같습니다:

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

이를 구성해보겠습니다:

  • state: 현재 상태입니다. 게임 비유에서는 캐릭터의 현재 체력과 같습니다.
  • dispatch: 상태를 업데이트하기 위해 사용하는 함수입니다.
  • reducer: 상태가 어떻게 변할지 지정하는 함수입니다.
  • initialState: 애플리케이션의 시작 상태입니다.

지금은 약간 혼란스러울 수 있지만, 걱정하지 마세요! 곧 실제로 보여드리면 이해가 될 것입니다.

reducer hook 적용하기

이제 useReducer가 어떻게 작동하는지 이해하기 위해 간단한 카운터 애플리케이션을 만들어보겠습니다. 기본 설정으로 시작하고 그 위에 올리겠습니다.

import React, { useReducer } from 'react';

// Step 1: 초기 상태 정의
const initialState = { count: 0 };

// Step 2: reducer 함수 생성
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}

// Step 3: Counter 컴포넌트 생성
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);

return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}

export default Counter;

이를 단계별로 설명해보겠습니다:

  1. useReducer를 React에서 import합니다.
  2. initialState를 카운트가 0인 상태로 정의합니다.
  3. 현재 상태와 액션을 기반으로 새로운 상태를 반환하는 reducer 함수를 생성합니다.
  4. Counter 컴포넌트에서 useReducer를 사용하여 현재 상태와 dispatch 함수를 얻습니다.
  5. 현재 카운트와 두 개의 버튼을 렌더합니다. '+' 버튼은 'increment' 액션을 디스패치하고, '-' 버튼은 'decrement' 액션을 디스패치합니다.

'+' 버튼을 클릭하면 'increment' 액션을 디스패치하여 카운트를 증가시키고, '-' 버튼은 'decrement' 액션을 디스패치하여 카운트를 감소시킵니다.

useReducer 사용하기

이제 기본 예제를 보았으니, 더 복잡한 시나리오를 탐구해보겠습니다. 우리는 간단한 작업 관리 애플리케이션을 만들어 useReducer를 사용하여 작업을 추가하고 제거하는 방법을 보겠습니다.

import React, { useReducer, useState } from 'react';

// Step 1: 초기 상태 정의
const initialState = { tasks: [] };

// Step 2: reducer 함수 생성
function reducer(state, action) {
switch (action.type) {
case 'ADD_TASK':
return { tasks: [...state.tasks, action.payload] };
case 'REMOVE_TASK':
return { tasks: state.tasks.filter((task, index) => index !== action.payload) };
default:
return state;
}
}

// Step 3: TaskManager 컴포넌트 생성
function TaskManager() {
const [state, dispatch] = useReducer(reducer, initialState);
const [newTask, setNewTask] = useState('');

const handleAddTask = () => {
if (newTask.trim()) {
dispatch({ type: 'ADD_TASK', payload: newTask });
setNewTask('');
}
};

const handleRemoveTask = (index) => {
dispatch({ type: 'REMOVE_TASK', payload: index });
};

return (
<div>
<input
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="새로운 작업 입력"
/>
<button onClick={handleAddTask}>작업 추가</button>
<ul>
{state.tasks.map((task, index) => (
<li key={index}>
{task}
<button onClick={() => handleRemoveTask(index)}>제거</button>
</li>
))}
</ul>
</div>
);
}

export default TaskManager;

이 더 복잡한 예제에서:

  1. initialState는 작업의 배열을 가집니다.
  2. reducer 함수는 'ADD_TASK'와 'REMOVE_TASK' 두 가지 액션을 처리합니다.
  3. TaskManager 컴포넌트에서는 useReducer를 작업 관리에 사용하고, useState를 입력 필드 관리에 사용합니다.
  4. 작업을 추가하고 제거하는 함수를 정의하고, 이 함수들이 적절한 액션을 디스패치합니다.
  5. 새로운 작업을 입력할 수 있는 입력 필드와 추가 버튼, 현재 작업 목록과 각 작업에 대한 제거 버튼을 렌더합니다.

이 예제는 useReducer가 복잡한 상태 로직을 깔끔하고 정리된 방식으로 관리하는 데 어떻게 도움이 되는지 보여줍니다.

메서드 표

여기서 다루었던 주요 메서드와 개념을 요약하는 표를 제공합니다:

메서드/개념 설명 예제
useReducer 복잡한 상태 로직을 관리하는 React hook const [state, dispatch] = useReducer(reducer, initialState);
reducer 상태가 어떻게 변할지 지정하는 함수 function reducer(state, action) { ... }
dispatch 상태를 업데이트하기 위해 사용하는 함수 dispatch({ type: 'ADD_TASK', payload: newTask })
액션 상태에 어떤 변화를 가져올지 설명하는 객체 { type: 'INCREMENT' }
초기 상태 애플리케이션의 시작 상태 const initialState = { count: 0 };

useReducer를 효과적으로 사용하는 데는 연습이 필요합니다. 즉시 이해가 되지 않는다면 낙담하지 마세요 - 경험 많은 개발자들도 새로운 개념을 이해하는 데 시간이 필요합니다. 계속 코딩하고 실험하고, 가장 중요한 것은 즐겁게 만들어보세요! 당신이 복잡한 상태를 프로처럼 관리할 수 있을 때까지입니다. 행복하게 코딩하세요!

Credits: Image by storyset