처음 배우는 Redux Toolkit: 쉬운 카운터 앱 만들기

odada·2025년 1월 7일
0

next.js

목록 보기
11/12

목차 🚀

  1. Redux 기본 개념
  2. 프로젝트 설정하기
  3. 카운터 앱 만들기
  4. 추가 학습 자료

1. Redux 기본 개념

1.1. Redux가 뭔가요? 🤔

Redux는 React 앱에서 데이터를 관리하는 도구입니다.
마치 은행처럼 생각해보세요:

  • Store (은행 금고): 모든 데이터를 보관하는 곳
  • Actions (거래 요청서): 데이터 변경을 요청하는 방법
  • Reducers (은행원): 실제로 데이터를 변경하는 함수
  • Dispatch (은행 창구): 액션을 전달하는 함수

1.2. Redux가 왜 필요한가요? 🧐

React에서 컴포넌트 간 데이터 공유가 필요할 때:

// 🔴 Redux 없이 - props drilling 문제 발생
function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <Header count={count} />
      <Main count={count} setCount={setCount} />
      <Footer count={count} />
    </div>
  );
}

// ✅ Redux 사용 - 어디서든 쉽게 데이터 접근
function AnyComponent() {
  const count = useSelector(state => state.counter.value);
  // 데이터를 props로 전달받을 필요 없음!
}

1.3. Redux의 작동 방식 📝

데이터가 변경되는 과정을 순서대로 살펴봅시다:

  1. 사용자 동작 발생

    // 버튼 클릭 등의 이벤트 발생
    <button onClick={() => dispatch(increment())}>
      증가
    </button>
  2. Action 생성

    // increment() 함수가 다음과 같은 액션 객체 생성
    {
      type: 'counter/increment'
    }
  3. Reducer 실행

    // 리듀서가 액션을 처리하여 새로운 상태 생성
    const counterReducer = (state = { value: 0 }, action) => {
      switch (action.type) {
        case 'counter/increment':
          return { value: state.value + 1 };
        default:
          return state;
      }
    }
  4. Store 업데이트

    // 새로운 상태가 스토어에 저장됨
    store = { counter: { value: 1 } }
  5. 컴포넌트 업데이트

    // 변경된 상태를 사용하는 컴포넌트가 리렌더링
    const count = useSelector(state => state.counter.value);
    // count 값이 바뀌어서 화면 갱신

2. 프로젝트 설정하기

2.1. 프로젝트 생성

# Next.js 프로젝트 생성
npx create-next-app@latest redux-counter --typescript --tailwind --eslint

# 필요한 패키지 설치
npm install @reduxjs/toolkit react-redux

2.2. 폴더 구조 만들기

src/
  ├── store/              # Redux 관련 폴더
  │   ├── slices/        # 리듀서와 액션들
  │   │   └── counterSlice.js
  │   └── index.js       # 스토어 설정
  │
  ├── components/         # 리액트 컴포넌트
  │   └── Counter.js
  │
  └── app/               # Next.js 페이지
      └── page.js

3. 카운터 앱 만들기

3.1. Redux 슬라이스 만들기

// src/store/slices/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,          // 카운터 값
    status: 'idle'     // 상태 표시 (예: 로딩 상태)
  },
  reducers: {
    // 증가 기능
    increment: (state) => {
      state.value += 1;
      // Redux Toolkit은 직접 수정해도 됩니다!
      // (내부적으로 불변성 관리를 해줌)
    },
    
    // 감소 기능
    decrement: (state) => {
      state.value -= 1;
    },
    
    // 특정 값만큼 증가
    incrementByAmount: (state, action) => {
      // action.payload로 전달된 값만큼 증가
      state.value += action.payload;
    },
    
    // 상태 변경
    setStatus: (state, action) => {
      state.status = action.payload;
    }
  }
});

// 액션 생성자들 내보내기
export const { 
  increment, 
  decrement, 
  incrementByAmount,
  setStatus 
} = counterSlice.actions;

// 리듀서 내보내기
export default counterSlice.reducer;

3.2. 스토어 설정하기

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './slices/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer
  }
});

3.3. Provider 설정하기

// src/app/layout.js
"use client";
import { Provider } from 'react-redux';
import { store } from '@/store';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Provider store={store}>
          {children}
        </Provider>
      </body>
    </html>
  );
}

3.4. 카운터 컴포넌트 만들기

// src/components/Counter.js
"use client";
import { useSelector, useDispatch } from 'react-redux';
import {
  increment,
  decrement,
  incrementByAmount,
  setStatus
} from '@/store/slices/counterSlice';

export default function Counter() {
  // Redux 상태 가져오기
  const count = useSelector((state) => state.counter.value);
  const status = useSelector((state) => state.counter.status);
  
  // 디스패치 함수 가져오기
  const dispatch = useDispatch();

  // 5만큼 증가시키는 함수 (로딩 상태 포함)
  const handleIncreaseByFive = () => {
    // 로딩 상태로 변경
    dispatch(setStatus('loading'));
    
    // 0.5초 후에 값 증가 및 상태 변경
    setTimeout(() => {
      dispatch(incrementByAmount(5));
      dispatch(setStatus('complete'));
    }, 500);
  };

  return (
    <div className="p-8 max-w-md mx-auto">
      <div className="bg-white rounded-lg shadow-md p-6">
        {/* 제목 */}
        <h1 className="text-2xl font-bold text-center mb-6">
          Redux 카운터
        </h1>
        
        {/* 카운터 값 표시 */}
        <div className="text-center mb-4">
          <div className="text-4xl font-bold text-blue-600">
            {count}
          </div>
          <div className="text-sm text-gray-500 mt-1">
            상태: {status}
          </div>
        </div>
        
        {/* 버튼들 */}
        <div className="flex gap-2 justify-center">
          <button
            onClick={() => dispatch(increment())}
            className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
          >
            증가 (+1)
          </button>
          
          <button
            onClick={() => dispatch(decrement())}
            className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors"
          >
            감소 (-1)
          </button>
          
          <button
            onClick={handleIncreaseByFive}
            className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors"
            disabled={status === 'loading'}
          >
            {status === 'loading' ? '처리 중...' : '5 증가'}
          </button>
        </div>
      </div>
    </div>
  );
}

3.5. 페이지에 적용하기

// src/app/page.js
import Counter from '@/components/Counter';

export default function Home() {
  return (
    <main className="min-h-screen bg-gray-100 py-12">
      <Counter />
    </main>
  );
}

4. 추가 학습 자료

4.1. Redux DevTools 사용하기

  1. Chrome 웹 스토어에서 "Redux DevTools" 설치
  2. 개발자 도구(F12) > Redux 탭 열기
  3. 상태 변화 추적하기:
    • Action 탭: 발생한 모든 액션 확인
    • State 탭: 현재 상태 확인
    • Diff 탭: 상태 변화 확인

4.2. 자주 하는 실수들

// ❌ 잘못된 방법: 직접 상태 변경
const wrongReducer = (state, action) => {
  state.value = 123;  // 일반 Redux에서는 이렇게 하면 안됨!
}

// ✅ 올바른 방법: 새로운 상태 반환
const correctReducer = (state, action) => {
  return {
    ...state,
    value: 123
  };
}

// 🎉 Redux Toolkit을 사용하면 직접 수정해도 됨!
const toolkitReducer = (state, action) => {
  state.value = 123;  // OK!
}

4.3. 성능 최적화 팁

// ❌ 비효율적인 방법
const data = useSelector(state => {
  return state.items.filter(item => item.completed);
});

// ✅ 효율적인 방법
const selectCompletedItems = state => 
  state.items.filter(item => item.completed);
const data = useSelector(selectCompletedItems);

4.4. 다음 단계로 배울 내용

  1. Async Thunks로 비동기 작업 처리하기
  2. createEntityAdapter로 데이터 정규화하기
  3. Redux Toolkit Query (RTK Query) 사용하기
  4. Middleware 만들기

이제 여러분은 Redux Toolkit을 사용하여 간단한 카운터 앱을 만들 수 있게 되었습니다! 🎉
더 복잡한 앱을 만들 때도 이 기본 개념들이 그대로 적용됩니다.

0개의 댓글