Reducer 패턴이란 무엇인가?

김재형·2024년 7월 30일
1
post-thumbnail
post-custom-banner

시작하기에 앞서

Workspace X 앱을 구성할 때, TCA 를 사용하여 앱을 제작했는데
Reducer 패턴을 적용한 TCA 를 좀 더 이해하기 위해
Reducer 패턴이란 무엇인가를 주제로 글을 쓰게 되었습니다.

Reducer

리듀서 패턴을 배우기 전, 리듀서가 무엇인지 알아야 할듯합니다.
Reducer란?
함수형 프로그래밍에서 유래된 개념으로 상태(State)와 액션(Action)을 받아서 새로운 상태를 반환하는 함수이다. 라고 되어 있는데요 이해를 위해 iOS의 기본 패턴인 MVC 를 다시 살펴보도록 하겠습니다.

MVC

View에서 이벤트가 발생하면 Controller에 알리고
Controller가 이벤트를 처리하면 Model에 업데이트를 명령합니다.
Model은 업데이트한 후 컨트롤러에 알린 후 컨트롤러는 이를 View에 알리는 구조였죠

MVC 패턴의 장점은 유연성과 양방향성이었습니다.
단점으론 코드가 방대해지고, 체인 형식으로 업데이트가 이루어져 그 경로를 찾기 어려워지는 구조였습니다.

다시 Reducer란 이 "이전 상태와 동작을 받아 새 상태를 리턴하는 순수 함수를 말합니다."

순수함수..?

순수 함수란 같은 인자가 들어오면 항상 같은 값이 나와야 하며, return 값으로만 소통하고 데이터
베이스 혹은 네트워크 호출등 외부의 데이터 구조를 변형하는 호출을 허용하지 않는 함수를 말합니다.

Reducer 패턴이란

App의 상태 관리를 위해 리듀서 함수를 통해 상태 변화를 정의하는 디자인 패턴입니다.
단반향 데이터 흐름을 기반으로 합니다.

구성 요소

  • 상태 (State): 애플리케이션의 현재 상태를 나타내는 객체
  • 액션 (Action): 상태를 변경하기 위한 이벤트를 나타내는 객체
  • 리듀서 (Reducer): 현재 상태와 액션을 받아 새로운 상태를 반환하는 순수 함수
  • 스토어 (Store): 상태와 리듀서를 포함하고, 액션을 통해 상태를 업데이트하는 객체

예시 코드를 통해 이해하기

State 상태

App의 현재 상태를 나타내는 구조체 입니다.

struct ExState: Equatable {
    var counter: Int = 0
}

Action (행위)

상태를 변경하기위한 이벤트 정의

enum ExAction {
    case increment(amount: Int)
    case decrement(amount: Int)
}

Reducer (리듀서 함수 정의)

현재 상태와 액션을 받아서 새로운 상태를 반환하는 순수함수

func ExReducer(state: inout AppState, action: AppAction) {
    switch action {
    case .increment(let amount):
        state.counter += amount
    case .decrement(let amount):
        state.counter -= amount
    }
}

store

상태와 리듀서를 포함하고 상태를 업데이트

class Store: ObservableObject {
    @Published private(set) var state: AppState
    private let reducer: (inout ExState, ExAction) -> Void
    
    init(initialState: AppState, reducer: @escaping (inout ExState, ExAction) -> Void) {
        self.state = initialState
        self.reducer = reducer
    }
    
    func dispatch(action: AppAction) {
        reducer(&state, action)
    }
}

### 사용시
ContentView(store: Store(initialState: ExState(), reducer: ExReducer))

store.dispatch(action: .increment(amount: 1))

마무리 하며

상당히 흥미로운 패턴을 다루어본 것 같습니다.
블로그 작성이 늦어 져서 죄송합니다. ㅠㅠ 과제하느라 작성을 못했었네요 ㅠㅠ
오늘 하루도 모두 고생하였습니다!

profile
IOS 개발자 새싹이
post-custom-banner

0개의 댓글