본문으로 건너뛰기

Redux Toolkit이 오늘날 Redux 사용 방식인 이유

비공식 베타 번역

이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →

Redux Toolkit이란?

Redux Toolkit(줄여서 "RTK")은 Redux 로직 작성을 위한 공식 권장 접근 방식입니다. @reduxjs/toolkit 패키지는 핵심 redux 패키지를 감싸며, Redux 애플리케이션 구축에 필수적인 API 메서드와 공통 의존성을 포함합니다. Redux Toolkit은 권장 모범 사례를 내장하고, 대부분의 Redux 작업을 단순화하며, 흔한 실수를 방지하고, Redux 애플리케이션 작성을 더 쉽게 만듭니다.

현재 어떤 Redux 로직을 작성하고 있다면, 반드시 Redux Toolkit을 사용하여 코드를 작성해야 합니다!

RTK에는 스토어 설정, 리듀서 생성 및 불변 업데이트 로직 작성, 상태의 전체 "슬라이스" 생성 등 다양한 일반적인 사용 사례를 단순화하는 유틸리티가 포함되어 있습니다.

첫 프로젝트를 설정하는 Redux 초보자이든 기존 애플리케이션을 간소화하려는 숙련된 사용자이든, **Redux Toolkit**을 통해 Redux 코드를 개선할 수 있습니다.

Redux Toolkit을 사용한 "현대적 Redux" 사용법을 배우려면 다음 페이지를 참고하세요:

Redux Toolkit과 Redux 코어의 차이점

"Redux"란 무엇인가?

먼저 "Redux란 무엇인가?"라는 질문을 던져야 합니다.

Redux는 본질적으로 다음과 같습니다:

  • "전역" 상태를 포함하는 단일 스토어

  • 애플리케이션에서 발생하는 이벤트 시 스토어에 일반 객체 액션을 디스패치

  • 순수 리듀서 함수가 해당 액션을 처리하고 불변적으로 업데이트된 상태 반환

필수는 아니지만, 일반적으로 Redux 코드는 다음을 포함합니다:

  • 해당 액션 객체를 생성하는 액션 생성자

  • 사이드 이펙트를 가능하게 하는 미들웨어

  • 사이드 이펙트가 포함된 동기/비동기 로직을 담은 썽크 함수

  • ID로 항목 조회가 가능한 정규화된 상태

  • 파생 데이터 최적화를 위한 Reselect 라이브러리의 메모이즈드 셀렉터 함수

  • 액션 기록 및 상태 변경을 확인할 수 있는 Redux DevTools 확장

  • 액션, 상태 및 기타 함수에 대한 TypeScript 타입

추가로, Redux는 일반적으로 React 컴포넌트가 Redux 스토어와 통신할 수 있도록 React-Redux 라이브러리와 함께 사용됩니다.

Redux 코어의 역할은?

Redux 코어는 매우 작고 의도적으로 제약이 없는 라이브러리입니다. 몇 가지 기본 API 프리미티브를 제공합니다:

  • Redux 스토어 생성용 createStore

  • 다중 슬라이스 리듀서를 단일 리듀서로 결합하는 combineReducers

  • 다중 미들웨어를 스토어 인핸서로 결합하는 applyMiddleware

  • 다중 스토어 인핸서를 단일 인핸서로 결합하는 compose

이 외에는 애플리케이션의 모든 Redux 관련 로직을 완전히 직접 작성해야 합니다.

좋은 소식은 이로 인해 Redux가 다양한 방식으로 사용될 수 있다는 점입니다. 나쁜 소식은 코드 작성을 쉽게 만들어주는 도우미가 전혀 없다는 것입니다.

예를 들어, 리듀서 함수는 단순히 함수일 뿐입니다. Redux Toolkit 이전에는 일반적으로 switch 문과 수동 업데이트로 리듀서를 작성했습니다. 또한 수동으로 작성한 액션 생성자와 액션 타입 상수가 함께 사용되었습니다:

Legacy hand-written Redux usage
const ADD_TODO = 'ADD_TODO'
const TODO_TOGGLED = 'TODO_TOGGLED'

export const addTodo = text => ({
type: ADD_TODO,
payload: { text, id: nanoid() }
})

export const todoToggled = id => ({
type: TODO_TOGGLED,
payload: id
})

export const todosReducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return state.concat({
id: action.payload.id,
text: action.payload.text,
completed: false
})
case TODO_TOGGLED:
return state.map(todo => {
if (todo.id !== action.payload) return todo

return {
...todo,
completed: !todo.completed
}
})
default:
return state
}
}

이 코드 중 어느 것도 redux 코어 라이브러리의 특정 API에 의존하지 않습니다. 하지만 작성해야 할 코드량이 상당합니다. 불변 업데이트를 위해선 수많은 객체 스프레드와 배열 연산을 수동으로 작성해야 했으며, 실수로 상태를 변경하기 쉽습니다(이것이 항상 Redux 버그의 1순위 원인입니다!). actions/todos.js, constants/todos.js, reducers/todos.js처럼 하나의 기능을 여러 파일에 분산시키는 것도 흔한 패턴이었습니다(비록 절대적으로 요구되진 않지만).

추가로, 스토어 설정은 거의 모든 Redux 앱에서 사용되는 표준 도구임에도 불구하고, thunk 같은 일반적인 미들웨어 추가나 Redux DevTools 확장 지원 활성화를 위해 일련의 단계를 거쳐야 했습니다.

Redux Toolkit은 무엇을 하나요?

이것들이 원래 Redux 문서에 소개된 패턴이었지만, 불행히도 매우 장황하고 반복적인 코드가 필요했습니다. 이 보일러플레이트 대부분은 Redux를 사용하는 데 필수적이지 않습니다. 게다가 보일러플레이트 코드는 실수할 기회를 더 많이 만들어냈습니다.

우리는 수동으로 작성하는 Redux 로직의 "보일러플레이트"를 제거하고, 흔한 실수를 방지하며, 표준 Redux 작업을 간소화하는 API를 제공하기 위해 특별히 Redux Toolkit을 만들었습니다.

Redux Toolkit은 모든 Redux 앱에서 가장 자주 수행하는 작업을 단순화하는 두 가지 핵심 API로 시작합니다:

  • configureStore: 단일 함수 호출로 리듀서 결합, thunk 미들웨어 추가, Redux DevTools 통합 설정을 포함한 완벽하게 구성된 Redux 스토어를 설정합니다. 또한 createStore보다 구성이 쉬운데, 명명된 옵션 매개변수를 사용하기 때문입니다.

  • createSlice: Immer 라이브러리를 사용해 state.value = 123처럼 "변경(mutating)"하는 JS 문법으로 불변 업데이트를 작성할 수 있게 합니다(스프레드 연산자 불필요). 또한 각 리듀서에 대한 액션 생성자 함수를 자동 생성하고, 리듀서 이름을 기반으로 내부적으로 액션 타입 문자열을 생성합니다. 마지막으로 TypeScript와 완벽하게 호환됩니다.

즉, 여러분이 작성하는 코드가 극적으로 간소화될 수 있습니다. 예를 들어, 동일한 todos 리듀서가 다음과 같이 간결해질 수 있습니다:

features/todos/todosSlice.js
import { createSlice } from '@reduxjs/toolkit'

const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
todoAdded(state, action) {
state.push({
id: action.payload.id,
text: action.payload.text,
completed: false
})
},
todoToggled(state, action) {
const todo = state.find(todo => todo.id === action.payload)
todo.completed = !todo.completed
}
}
})

export const { todoAdded, todoToggled } = todosSlice.actions
export default todosSlice.reducer

모든 액션 생성자와 액션 타입이 자동 생성되며, 리듀서 코드는 더 짧고 이해하기 쉽습니다. 각 상황에서 실제로 무엇이 업데이트되는지도 훨씬 명확해집니다.

configureStore를 사용하면 스토어 설정을 다음과 같이 간소화할 수 있습니다:

app/store.js
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'
import filtersReducer from '../features/filters/filtersSlice'

export const store = configureStore({
reducer: {
todos: todosReducer,
filters: filtersReducer
}
})

이 단일 configureStore 호출이 수동으로 수행하던 모든 일반적인 설정 작업을 자동으로 처리합니다:

  • 슬라이스 리듀서가 자동으로 combineReducers()에 전달됨

  • redux-thunk 미들웨어가 자동 추가됨

  • 실수로 인한 상태 변경을 잡기 위한 개발 모드 미들웨어 추가됨

  • Redux DevTools 확장이 자동 설정됨

  • 미들웨어와 DevTools 개선 도구(enhancer)가 함께 구성되어 스토어에 추가됨

동시에 configureStore는 기본 동작을 수정할 수 있는 옵션을 제공합니다(예: thunk 비활성화 및 saga 추가, 프로덕션 환경에서 DevTools 비활성화 등).

이 외에도 Redux Toolkit에는 일반적인 Redux 작업을 위한 다른 API가 포함됩니다:

  • createAsyncThunk: 비동기 요청 전후에 액션을 디스패치하는 표준 패턴 추상화

  • createEntityAdapter: 정규화된 상태에서 CRUD 작업을 위한 사전 구축된 리듀서 및 셀렉터

  • createSelector: 메모이제이션된 셀렉터를 위한 표준 Reselect API 재익스포트

  • createListenerMiddleware: 디스패치된 액션에 응답하여 로직을 실행하는 사이드 이펙트 미들웨어

마지막으로 RTK 패키지에는 'RTK Query'도 포함되어 있습니다. 이는 Redux 앱을 위한 완전한 데이터 가져오기 및 캐싱 솔루션으로, 별도의 선택적 엔트리 포인트인 @reduxjs/toolkit/query에서 제공됩니다. 엔드포인트(REST, GraphQL 또는 모든 비동기 함수)를 정의할 수 있으며, 데이터 가져오기, 로딩 상태 업데이트, 결과 캐싱을 완전히 관리하는 리듀서와 미들웨어를 생성합니다. 또한 const { data, isFetching } = useGetPokemonQuery('pikachu')처럼 컴포넌트에서 데이터를 가져오는 데 사용할 수 있는 React 훅을 자동으로 생성합니다.

이러한 각 API는 완전히 선택 사항이며 특정 사용 사례를 위해 설계되었습니다. 앱에서 실제로 사용할 API를 선택적으로 적용할 수 있습니다. 다만, 해당 작업에 도움이 되도록 모든 API를 적극 권장합니다.

Redux Toolkit은 여전히 'Redux'입니다! 단일 스토어 존재, 업데이트를 위한 액션 객체 디스패치, 상태를 불변적으로 업데이트하는 리듀서 등 핵심 개념은 동일합니다. 여기에 비동기 로직을 위한 썽크(thunk), 정규화된 상태 관리, TypeScript 타입 지정, DevTools 사용 등도 가능합니다. 동일한 결과를 얻기 위해 작성해야 하는 코드량이 훨씬 줄었을 뿐입니다!

Redux Toolkit 사용을 권장하는 이유

Redux 관리자로서 저희의 의견은 다음과 같습니다:

모든 Redux 사용자에게 Redux Toolkit으로 코드를 작성할 것을 권장합니다. 코드를 간소화할 뿐만 아니라 일반적인 Redux 실수와 버그를 대부분 제거해주기 때문입니다!

초기 Redux 패턴의 '보일러플레이트'와 복잡성은 Redux의 필수 요소가 절대 아니었습니다. 해당 패턴이 존재했던 이유는 다음과 같습니다:

  • 최초의 'Flux 아키텍처'가 일부 동일한 접근 방식을 사용했음

  • 초기 Redux 문서가 타입별로 코드를 분리하기 위해 액션 타입 상수 등을 보여줬음

  • JavaScript는 기본적으로 가변(mutable) 언어이며, 불변 업데이트 작성에는 수동 객체 스프레드 및 배열 업데이트가 필요했음

  • Redux는 원래 몇 주 만에 구축되었으며 의도적으로 소수의 API 기본 요소로 설계됨

추가로 Redux 커뮤니티에서 특정 접근 방식을 채택하며 보일러플레이트가 증가했습니다:

  • 사이드 이펙트 작성의 일반적인 접근법으로 redux-saga 미들웨어 사용 강조

  • Redux 액션 객체에 대한 TS 타입을 수동으로 작성하고 유니온 타입을 생성해 타입 수준에서 디스패치 가능한 액션 제한

수년간 실제로 사용자들이 Redux를 어떻게 활용하는지 관찰했습니다. 커뮤니티가 액션 타입/생성기 생성, 비동기 로직 및 사이드 이펙트, 데이터 가져오기 등을 위해 수백 개의 애드온 라이브러리를 개발하는 모습도 보았습니다. 사용자들이 꾸준히 겪는 문제들도 목격했습니다: 실수로 상태 변경(mutate), 단순 상태 업데이트에 수십 줄의 코드 작성, 코드베이스 구조 파악 어려움 등이 대표적입니다. 수천 명의 사용자가 Redux 학습 및 사용 시 조각들을 통합하는 방법을 이해하지 못해 어려움을 호소하거나, 다수의 개념과 과도한 코드 작성에 혼란스러워하는 모습을 도왔습니다. 사용자가 직면한 문제를 정확히 파악하고 있습니다.

바로 이러한 문제들을 해결하기 위해 Redux Toolkit을 설계했습니다!

  • Redux Toolkit은 스토어 설정을 단일 명확한 함수 호출로 단순화하되, 필요한 경우 스토어 옵션을 완전히 구성할 수 있는 기능은 유지합니다.

  • Redux Toolkit은 Redux 버그의 1순위 원인인 의도치 않은 상태 변경(mutation)을 제거합니다.

  • Redux Toolkit은 액션 생성기나 액션 타입을 수동으로 작성할 필요를 없앱니다.

  • Redux Toolkit은 오류 발생 가능성이 높은 불변 업데이트 로직 수동 작성을 제거합니다.

  • Redux Toolkit은 하나의 파일에 Redux 기능 코드를 작성하기 쉽게 해주며, 여러 분리된 파일에 흩어져 작성할 필요가 없습니다.

  • Redux Toolkit은 우수한 TS 지원을 제공하며, 탁월한 타입 안전성을 부여하고 코드에서 정의해야 하는 타입 수를 최소화하도록 설계된 API를 갖추고 있습니다.

  • RTK Query는 데이터 가져오기 관리 및 로딩 상태 추적을 위한 썽크(thunk), 리듀서, 액션 생성기, 이펙트 훅을 전혀 작성할 필요가 없게 해줍니다.

이러한 이유로:

사용자분들은 반드시 Redux Toolkit(@reduxjs/toolkit 패키지)을 사용해야 하며, 새로운 Redux 코드 작성 시 레거시 redux 코어 패키지는 사용하지 않아야 합니다!

기존 애플리케이션의 경우라도 최소한 createStore 대신 configureStore로 전환할 것을 권장합니다. 개발 모드 미들웨어가 기존 코드베이스에서 의도치 않은 변이(mutation)와 직렬화 가능성(serializability) 오류를 잡아내는 데 도움을 주기 때문입니다. 또한 가장 많이 사용하는 리듀서(그리고 향후 작성할 모든 리듀서)를 createSlice로 전환하도록 권장합니다. 코드가 더 짧아지고 이해하기 쉬워질 뿐만 아니라 안전성 향상으로 인해 시간과 노력을 절약할 수 있습니다.

redux 코어 패키지는 여전히 작동하지만, 현재는 구식으로 간주됩니다. 모든 API는 @reduxjs/toolkit에서 다시 내보내지며, configureStorecreateStore가 수행하는 모든 기능을 더 나은 기본 동작과 구성 가능성으로 제공합니다.

저수준 개념을 이해하는 것은 Redux Toolkit이 사용자를 대신해 수행하는 작업을 더 잘 이해하는 데 유용합니다. 그래서 "Redux Fundamentals" 튜토리얼은 추상화 없이 Redux가 어떻게 작동하는지 보여줍니다. 하지만 이러한 예제는 순전히 학습 도구로 제시되며, 마지막에는 Redux Toolkit이 기존에 수작업으로 작성된 Redux 코드를 어떻게 단순화하는지 보여줍니다.

redux 코어 패키지를 단독으로 사용 중이라면 코드는 계속 작동할 것입니다. 하지만 @reduxjs/toolkit으로 전환하고 코드를 Redux Toolkit API를 사용하도록 업데이트할 것을 강력히 권장합니다!

추가 정보

자세한 내용은 다음 문서 페이지와 블로그 글을 참조하세요: