TCA) computed property로 Filtering 할 때 주의점

SteadySlower·2023년 5월 17일
0

TCA를 사용하다가 실수한 케이스를 포스팅 해보겠습니다.

IdentifiedArray Filtering

TCA 예제에 보면 IdentifiedArray의 원소 중에 특정 조건을 만족하는 원소들만을 View에 보여주기 위해서 고차함수 filter와 computed property를 사용하는 아래와 같은 코드가 있습니다.

하위 View에서의 action을 모두 인식하고 state가 변환되는 경우에도 View가 갱신되는 것을 볼 수 있습니다.

var filteredTodos: IdentifiedArrayOf<Todo.State> {
  switch filter {
  case .active: return self.todos.filter { !$0.isComplete }
  case .all: return self.todos
  case .completed: return self.todos.filter(\.isComplete)
  }
}
List {
  ForEachStore(
    self.store.scope(state: \.filteredTodos, action: Todos.Action.todo(id:action:))
  ) {
    TodoView(store: $0)
  }
}

🚫 새로운 IdentifiedArray를 만들지 마세요!

문제 코드

하지만 아래처럼 computed property 안에서 완전히 새로운 IdentifiedArray를 만들어서 전달하는 경우 문제가 발생할 수 있습니다.

var filteredTodos: IdentifiedArrayOf<Todo.State> {
  switch filter {
  case .active: return self.todos.filter { !$0.isComplete }
  case .all: return self.todos
  case .completed:
      return IdentifiedArray(uniqueElements:
                        self.todos
                            .map {  }
                            .filter(\.isComplete)
      )
  }
}

문제 상황

  1. 필터링한 todo만 리스트에 보입니다.
  2. action도 모두 인식하고 state도 변화합니다. (콘솔에는 찍힘)
  3. 하지만 view가 갱신되지는 않습니다.

문제 원인 (뇌피셜😅)

아직 TCA의 내부 구현을 완전히 파악을 하지는 못했지만 제가 생각한 원인은 이렇습니다. 좀 더 공부해보고 틀렸으면 수정하겠습니다. 일단 저렇게 하면 안된다는 것만 알아주세요~^^

  1. 필터링한 todo가 보이는 이유
    1. 일단 리턴한 IdentifiedArray가 View를 그리는데 사용합니다.
    2. 따라서 ViewStore는 해당 IdentifiedArray 객체를 가지고 있습니다. (앞으로 IdentifiedArray-1이라고 부르겠습니다)
    3. 하지만 Store에서 computed property가 리턴되면 Store는 더이상 해당 IdentifiedArray-1를 가지고 있지 않습니다.
  2. Action이 인식된 이유
    1. 일단 ViewStore는 View를 그리는데 사용한 IdentifiedArray-1을 가지고 있습니다.
    2. 따라서 Action도 인식합니다.
    3. ViewStore는 Store에 Action이 인식되었다고 보냅니다.
    4. Store의 Reducer는 Action이 일어난 todo객체를 id를 활용해서 구분, 해당 Action을 처리하고 State를 갱신합니다.
  3. View 갱신은 안되는 이유
    1. State가 갱신이 되었으므로 Store는 ViewStore에 View를 갱신하라고 합니다.
    2. 하지만 갱신된 View는 원래 Store에 있는 IdentifiedArray이고 ViewStore가 View를 그리는데 사용한 것은 IdentifiedArray-1입니다.
    3. 따라서 IdentifiedArray-1 입장에서는 하나도 바뀐 것이 없습니다.
    4. View를 당연히 갱신하지 않습니다.

마치며…

기존의 MVVM의 프로젝트를 TCA로 변환하는 작업 중에 마주친 버그입니다. TCA는 제가 MVVM을 하면서 고민한 수많은 아키텍쳐에 관한 고민을 해결해주는 동시에 새로운 고민을 던져주었습니다.

시간을 내서 TCA에 대한 경험을 더 포스팅 해보도록 하겠습니다.

profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글