Redux를 활용한 상태 관리 - redux toolkit

박기찬·2023년 6월 30일
1

Web tech

목록 보기
3/9
post-thumbnail

React 애플리케이션을 개발할 때 상태 관리는 매우 중요한 요소입니다. 상태가 커지고 복잡해질수록 관리하기가 매우 어려워 집니다. 이런 문제를 해결하기 위해 Redux는 강력한 상태 관리 라이브러리로써 많은 개발자들에게 현재까지도 사랑받고 있습니다. 이 포스팅에서는 Redux를 소개하고, 어떻게 Redux를 활용하여 상태를 관리할 수 있는지 알아보겠습니다. 또한, Redux를 더 효율적으로 사용할 수 있게 도와주는 도구인 Redux toolkit에 대해 알아보겠습니다.

Redux가 필요한 이유

React와 같은 UI 컴포넌트 기반의 라이브러리나 프레임워크에서는 컴포넌트 간에 데이터를 공유하고 상태를 관리해야 하는 상황이 발생합니다. 일반적으로 컴포넌트 간에 데이터를 전달하려면 상위 컴포넌트에서 props를 통해 전달하고, 상태를 업데이트하려면 상위 컴포넌트의 setState 메서드를 호출해야 합니다. 이런 방식은 컴포넌트의 구조가 복잡해지고 컴포넌트 간의 데이터 흐름을 관리하기 어렵게 만들 수 있습니다.

또한, 애플리케이션 규모가 커질수록 상태 관리가 더욱 복잡해지는데, 컴포넌트 간의 상태 공유, 비동기 작업 처리, 상태 업데이트의 일관성 유지 등의 문제가 발생합니다. 이런 상황에서 Redux는 복잡한 상태 관리를 단순하고 예측 가능하게 만들기 위해 등장하였습니다.

Redux는 단일 소스원칙과 상태의 불변성을 강조하며, 애플리케이션의 상태를 하나의 스토어에 저장하고 관리합니다. 이를 통해 모든 컴포넌트가 동일한 상태에 접근하고 업데이트를 수신할 수 있습니다. 또한, 액션과 리듀서를 통해 상태 변화를 관리하고, 예측 가능한 상태 업데이트를 제공합니다.

Redux의 등장은 컴포넌트 간의 데이터 흐름을 효율적으로 관리하고 상태 관리를 예측 가능한 방식으로 해결하기 위한 필요성에서 비롯되었습니다. 그 결과로, Redux는 React를 비롯한 다양한 UI 라이브러리와 함께 사용되며, 대규모 애플리케이션의 상태 관리에 널리 사용되고 있습니다.


Redux의 기초를 이루는 세 가지 원칙

단일 소스원칙 (Single Source of Truth)

Redux는 애플리케이션의 전역 상태를 하나의 스토어(store)에 저장합니다. 이 스토어는 애플리케이션의 상태를 단일 소스로 관리하고 업데이트합니다. 이를 통해 상태의 일관성과 예측 가능성을 유지할 수 있습니다.

상태는 읽기 전용(Immutable)이다.

Redux에서 상태는 불변성(Immutable)을 유지해야 합니다. 상태를 변경하려면 기존 상태를 변경하는 대신 새로운 상태 객체를 반환해야 합니다. 이를 통해 상태 변경을 추적하고 시간적인 흐름에 따른 버그를 줄일 수 있습니다.

변화는 순수 함수로 작성된 리듀서에 의해 이루어진다.

Redux에서 애플리케이션의 상태 변경은 액션(action)을 통해 이루어집니다. 액션은 변화를 나타내는 객체입니다. 액션은 리듀서(reducer)라는 순수 함수에 전달되어 상태의 변화를 처리하고 새로운 상태를 반환합니다. 리듀서는 이전 상태와 액션을 입력으로 받아 새로운 상태를 반환하는데, 순수 함수로 작성되어 부작용이 없어야 합니다

정리하자면,

리덕스를 사용하면 스토어를 사용하여 상태를 컴포넌트 구조의 바깥에, 스토어를 중간자에 두어서 새로운 상태를 전달받거나 기존 상태를 업데이트 합니다. 이런 방식은 기존의 여러 컴포넌트를 거쳐서 받아오는 불필요한 과정 없이 어떤 위치에 컴포넌트가 있더라도 직속 부모 컴포넌트에게서 데이터를 받아오는 것 처럼 원하는 값을 골라서 데이터를 편리하게 받아오고, 관리할 수 있습니다.

그렇다면 Redux에서 사용되는 핵심 용어들은 어떤것이 있을까요?

액션 (Action)

액션은 상태 변화를 일으키기 위해 발생하는 이벤트 또는 작업을 나타냅니다. 일반적으로 객체 형태로 정의되며, 최소한의 정보인 type 필드를 가지고 있습니다. 예를 들어, "Login", "LoadData"와 같은 액션은 애플리케이션에서 어떤 변화를 발생시킬지 정의합니다.

액션 생성자 (Action Creator)

액션 생성자는 액션 객체를 생성하는 함수이며, 액션의 타입과 필요한 데이터를 전달받아 액션 객체를 반환합니다. 예를 들어 login 기능이 있다고 했을 때, login 액션 생성자는 사용자 이름과 비밀번호를 전달받아 로그인 액션 객체를 생성합니다.

리듀서 (Reducer)

Reducer는 액션에 따라 상태를 어떻게 업데이트할지 정의하는 순수 함수입니다. Reducer는 이전 상태와 액션 객체를 받아 새로운 상태를 반환하는데, 상태의 불변성을 유지하고 예측 가능한 상태 업데이트를 위해 이전 상태를 수정하지 않고 새로운 객체를 반환해야 합니다.

스토어 (Store)

스토어는 Redux 애플리케이션의 상태를 저장하는 단일 객체입니다. 애플리케이션의 모든 상태는 Store에 저장되고, Store는 상태의 변경과 액션 디스패치를 처리합니다. 또한, 상태를 가져오거나 변경하는 메서드를 제공하며, 리듀서를 등록하여 상태의 업데이트를 관리합니다.

디스패치 (Dispatch)

Dispatch는 액션을 스토어에 전달하는 메서드입니다. Dispatch를 통해 액션을 발생시키면 스토어는 해당 액션을 리듀서에 전달하여 상태를 업데이트합니다. 액션을 디스패치함으로써 상태 변화가 일어나고, 이에 따라 컴포넌트가 업데이트될 수 있습니다.

구독 (Subscribe)

Subscribe는 스토어의 상태 변경을 감지하고, 변경이 있을 때 콜백 함수를 호출하는 메서드입니다. Subscribe를 통해 컴포넌트는 상태의 변경을 실시간으로 감지하고, 필요한 업데이트를 수행할 수 있습니다.



이러한 리덕스는 리엑트에 종속되는 라이브러리가 아닙니다. 평범한 html과 javascript 환경에서도 사용할 수 있습니다. 하지만 본 포스팅에서는 react 환경에서의 사용을 예시로 들겠습니다.

Redux Toolkit

Redux를 더 효율적으로 사용할 수 있도록 도와주는 도구인 toolkit을 사용해 예시 코드와 함께 redux를 사용하는 방법을 기술하겠습니다.

Store

Redux Toolkit을 사용하여 스토어를 생성합니다. Redux Toolkit 은 스토어 생성을 단순화하는 configureStore 함수를 제공합니다.

import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers';

const store = configureStore({
  reducer: rootReducer
});

configureStore 함수를 호출하여 스토어를 생성할 수 있습니다. reducer 옵션에는 루트 리듀서가 포함된 객체를 전달합니다.

Action Types (createSlice)

Redux Toolkit에서는 액션 타입을 별도로 정의하지 않아도 됩니다. 대신에 Action과 관련된 로직을 정의하는 createSlice 함수를 사용합니다.

import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
  name: 'todo',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      state.push(action.payload);
    },
    removeTodo: (state, action) => {
      return state.filter(todo => todo.id !== action.payload.id);
    }
  }
});

export const { addTodo, removeTodo } = todosSlice.actions;
export default todosSlice.reducer;

위의 코드는 createSlice 함수를 사용하여 todo Slice를 생성하는 예시입니다. name은 Slice의 이름, initialState는 초기 상태, reducers는 액션과 관련된 로직을 정의하는 객체입니다. createSlice 함수는 액션 타입과 액션 생성자 함수를 자동으로 생성하므로 별도로 정의할 필요가 없습니다.

Reducers

Redux Toolkit에서는 리듀서 함수를 직접 작성할 필요가 없습니다. 앞서 사용한, createSlice 함수를 사용하여 액션과 관련된 로직을 정의하면 자동으로 리듀서 함수가 생성됩니다.

reducers: {
    addTodo: (state, action) => {
      state.push(action.payload);
    },
    removeTodo: (state, action) => {
      return state.filter(todo => todo.id !== action.payload.id);
    }
  }

위의 코드에서 reducers 객체에 정의된 함수들이 자동으로 리듀서 함수로 변환됩니다. 각 함수는 이전 상태를 변경하고 새로운 상태를 반환하는 로직을 가지고 있습니다.

Dispatch

Redux Toolkit에서도 Action을 Dispatch하는 방법은 기본적인 Redux 사용법과 동일합니다.

import store from './store';
import { addTodo, removeTodo } from './reducers/todosSlice';

store.dispatch(addTodo({ id: 1, text: 'Buy groceries' }));
store.dispatch(addTodo({ id: 2, text: 'Do laundry' }));
store.dispatch(removeTodo({ id: 1 }));

위의 코드는 todo 리스트에 1번과 2번 항목을 추가한 후에, 1번 항목을 삭제하는 예시입니다. 이처럼 Redux Toolkit을 사용하더라도 dispatch 메서드를 사용하여 Action을 Dispatch 할 수 있습니다. 액션 생성자 함수는 createSlice 함수에 의해 자동으로 생성되며, 필요한 액션 데이터를 인수로 전달합니다.


이와 같이, redux를 그냥 사용하는 것 보다는 redux toolkit을 사용하는 것이 좀 더 쉬워보입니다. 자세히 살펴보자면,

  • 코드량이 감소하고 가독성이 향상됩니다.

  • 액션 타입과 액션 생성자를 자동으로 생성하여 실수를 줄일 수 있습니다.

  • 불변성을 유지하기 위한 복잡한 작업을 자동으로 처리합니다.

  • 개발자 도구와의 통합이 용이합니다.

하지만, 단점도 존재합니다.

  • 복잡한 커스터마이징이 필요한 경우에는 제한적일 수 있습니다.

  • 기존 Redux의 전체 기능을 활용하는 것보다는 추상화된 인터페이스를 사용해야 합니다.


이런 단점에도 불구하고, Redux Toolkit은 Redux를 더 효율적으로 사용할 수 있도록 도와주는 도구이며, 개발 생산성과 유지보수성을 향상시키는데 도움을 줍니다. 또한 typeScript 사용자를 위해 action type, state type 등 TypeScript를 사용할 때 필요한 Type Definition을 공식 지원합니다.




https://ko.redux.js.org/understanding/thinking-in-redux/glossary
https://www.youtube.com/watch?v=bbkBuqC1rU4
https://flexiple.com/react/learn-redux-and-its-usage-with-react-by-building-books-finder-app/

profile
프론트엔드 개발자 🧑

0개의 댓글