본문 바로가기
React

[Next.js] Redux

by 2__50 2023. 8. 6.
공부한 내용을 정리한 글입니다 
내용에 오류가 있거나 더 좋은 의견이 있다면 댓글로 남겨주세요.
배움에 큰 도움이 됩니다. 🖋

 

 

Redux


http://prgssr.ru/development/pogruzhenie-v-react-redux.html

 

 

리액트 앱은 컴포넌트로 구성되고, 컴포넌트 내부에 저장되는 데이터인 상태(State)를 통해 동적인 UI를 만들 수 있다.
상태가 변경되면 해당 컴포넌트가 다시 렌더링되고, 변경된 값이 UI에 반영되는 것이다.

 

컴포넌트 구성이 복잡하지 않을 경우 컴포넌트 내부에서 상태를 관리하는 것이 효율적일 수 있다. 그러나 위 그림처럼 복잡할 경우, 컴포넌트 간의 데이터 흐름을 읽는 것이 쉽지 않다. 이럴 때 리덕스 사용을 고려해 볼 수 있다.

리덕스는 자바스크립트 앱의 상태를 관리하는 오픈 소스 라이브러리인데,
하나의 중앙 저장소에서 상태를 관리해 앱의 상태를 예측 가능하고 일관성 있게 관리한다.

 

리덕스 공식 홈페이지에서 소개하는 리덕스의 주요 특징은 다음과 같다.

 

 

예측 가능한 상태 변화

순수 함수인 리듀서를 통해 상태 변화를 관리하기 때문에, 상태 변경이 예측 가능하고 디버깅이 용이하다.
따라서 특정 액션에 의한 상태 변화가 항상 동일한 결과를 보장한다.


중앙 집중화된 상태 관리

상태를 중앙 집중화된 스토어에서 관리하므로, 상태의 변화를 예측 가능하고 관리하기 쉽게 만든다.
앱의 복잡성이 증가할 때도 상태 관리를 보다 체계적으로 할 수 있다.

 

시간여행과 디버깅

리덕스 상태의 변경 이력을 기록하고 추적할 수 있는 시간 여행 기능을 제공한다.
버그를 찾거나 이전 상태로 돌아가서 앱의 동작을 디버깅하는 데 유용하다.

 

유연함

리덕스는 UI 레이어와 상태 레이어를 분리하는 패턴을 따르며 특정 UI 라이브러리에 종속되지 않는다.
React, Angular, Vue.js와 같은 다양한 UI 라이브러리와 함께 사용할 수 있다.

 

 

 

주요 용어


 

https://medium.com/@gopikrishnag81/react-redux-5d4760852c11  /  https://ko.redux.js.org/tutorials/fundamentals/part-1-overview/

 

 

Store : 앱의 상태를 담고 있는 단일 객체. 앱의 전체 상태를 관리한다.
Action : 앱에서 일어나는 이벤트를 나타내는 객체. 상태를 변경하기 위해 발생시킨다.
Reducer : 상태 변경을 처리하는 순수 함수. 현재 상태와 액션을 받아서 새로운 상태를 반환한다.


Dispatch : 액션을 발생시켜 상태 변경을 트리거하는 메서드. 스토어의 상태를 변경한다.
Subscribe : 스토어의 상태가 변경될 때마다 호출되는 콜백 함수를 등록하는 메서드. 상태가 변경될 때마다 UI를 업데이트하거나 특정 작업을 수행하고 싶을 때 활용할 수 있다.

 

 

 

코드 예시


테마와 사용자 상태를 리덕스로 관리해보자.

먼저 각 상태에 관한 액션과 리듀서를 정의한다.

 


src/reducers/themeReducer.ts

import { AnyAction } from "redux";

// 상태 타입 정의
export enum ThemeType {
  LIGHT = "light",
  DARK = "dark",
}

export type AppState = {
  theme: ThemeType;
};

// 초기 상태
const initialState: AppState = {
  theme: ThemeType.DARK,
};

// 액션 타입 정의
enum ActionType {
  TOGGLE_THEME = "next-practice/theme/TOGGLE_THEME",
}

// 액션 타입에 맞는 액션 생성 함수 정의
type ToggleThemeAction = {
  type: ActionType.TOGGLE_THEME;
};

export const toggleTheme = (): ToggleThemeAction => {
  return { type: ActionType.TOGGLE_THEME };
};

// 리듀서 함수 정의
const themeReducer: Reducer<AppState, ToggleThemeAction> = (
  state = initialState,
  action
) => {
  switch (action.type) {
    case ActionType.TOGGLE_THEME:
      return {
        ...state,
        theme: state.theme === ThemeType.DARK ? ThemeType.LIGHT : ThemeType.DARK,
      };
    default:
      return state;
  }
};

export default themeReducer;

 

 

src/reducers/userReducer.ts

import { AnyAction } from "redux";

// 상태 타입 정의
export type UserState = {
  name: string;
  age: number;
};

// 초기 상태
const initialState: UserState = {
  name: "Kelly",
  age: 25,
};

// 액션 타입 정의
enum ActionType {
  UPDATE_USER = "next-practice/user/UPDATE_USER",
  ADD_USER = "next-practice/user/ADD_USER"
}

// 액션 타입에 맞는 액션 생성 함수 정의
type UserAction =
  | { type: ActionType.UPDATE_USER; payload: { name: string; age: number } }
  | { type: ActionType.ADD_USER; payload: { name: string; age: number } }

export const updateUser = (name: string, age: number): UpdateUserAction => {
  return { type: ActionType.UPDATE_USER, payload: { name, age } };
};

export const addUser = (name: string, age: number): UserAction => {
  return { type: ActionType.ADD_USER, payload: { name, age } };
};

// 리듀서 함수 정의
const userReducer: Reducer<UserState, UserAction> = (state = initialState, action) => {
  switch (action.type) {
    case ActionType.UPDATE_USER:
      return {
        ...state,
        name: action.payload.name,
        age: action.payload.age,
      };
    case ActionType.ADD_USER:
      return {
        ...state,
        name: action.payload.name,
        age: action.payload.age,
      };
    default:
      return state;
  }
};

export default userReducer;

 

 

combineReducers는 themeReducer와 userReducer를 해당하는 키로 매핑해 하나의 상태 객체로 결합한다(rootReducer). 이렇게 생성된 rootReducer는 앱 전체 상태를 관리하는데 사용된다. 

 

 

src/reducers/index.ts

import { combineReducers } from "redux";
import themeReducer from "./themeReducer";
import userReducer from "./userReducer";

const rootReducer = combineReducers({
  theme: themeReducer,
  user: userReducer,
});

export default rootReducer;​

 

 

configureStore 함수를 사용해 스토어를 생성한다.
이 스토어는 이제 앱 상태 관리의 중심 역할을 한다.

 

src/store.ts

import { configureStore } from "redux";
import rootReducer from "./reducers";

// 스토어 생성
const store = configureStore({ reducer: rootReducer });

export default store;

 

 

컴포넌트에서의 사용


 

<Provider> 로 앱을 감싸 리덕스 스토어를 리액트 앱 전체에 제공한다.
이제 앱 내의 모든 컴포넌트에서 리덕스의 상태 및 액션을 사용할 수 있게 된다.

 

 

src/index.ts

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

 

 

src/components/MyComponent/index.ts

import { useDispatch, useSelector } from "react-redux";

import React from "react";

const MyComponent = () => {
  // useDispatch 훅을 사용해 dispatch 함수를 가져온다.
  const dispatch = useDispatch();

  // useSelector 훅을 사용해 리덕스 상태를 읽는다.
  const theme = useSelector((state) => state.theme);

  // 테마를 변경하는 함수를 정의
  const toggleThemeHandler = () => {
    dispatch(toggleTheme());
  };

  return (
    <div>
      <h1>Current Theme: {theme}</h1>
      <button onClick={toggleThemeHandler}>Toggle Theme</button>
    </div>
  );
};

export default MyComponent;

 

 

 

참고


[도서] 실전에서 바로 쓰는 Next.js

 

실전에서 바로 쓰는 Next.js | 미셸 리바 - 교보문고

실전에서 바로 쓰는 Next.js | Next.js의 모든 기능을 낱낱이 파헤치고, 온라인 상거래 사이트까지 직접 구축해보는 웹 개발 실전서이 책의 강점은 리액트-Next.js를 함께 사용하는 방법과 Next.js를 단

product.kyobobook.co.kr

 

https://ko.redux.js.org/

 

Redux - 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너. | Redux

자바스크립트 앱을 위한 예측 가능한 상태 컨테이너.

ko.redux.js.org

 

'React' 카테고리의 다른 글

[React] 오픈소스 살펴보기_Hook의 구현체를 찾아서  (1) 2023.12.01
React에서의 상태관리  (0) 2023.02.13
React의 useMemo와 useCallback  (0) 2023.02.09
React Component와 Hooks의 Lifecycle  (0) 2023.02.09
[React] React vs Vue  (0) 2020.07.02

댓글