TCA) WithViewStore에서 if 분기문 사용할 때 주의점

SteadySlower·2023년 5월 18일
0

문제 상황

사이드 바를 통해서 세팅을 변경하고 그 세팅에 따라서 다른 Cell을 보여주는 View입니다. 의도한 동작은 setting을 변경하면 모든 Cell이 한꺼번에 변경이 되는 것입니다. 하지만 아래와 같이 LazyVStack 안에 if문을 작성하니 문제가 있었습니다.

preview에서는 원하는 대로 동작을 했습니다만 문제는 simulator에서 앱을 실행했을 때 였습니다. 원하는 대로 모든 Cell이 LazyVStack에서 이미 랜더링된 것은 그냥 이전의 mode가 그대로 나오고 새로 랜더링되는 것만 모드가 바뀌었습니다.

ScrollView {
    LazyVStack(spacing: 32) {
        if vs.setting.studyViewMode == .normal {
            ForEachStore(
              self.store.scope(state: \.words, action: WordList.Action.word(id:action:))
            ) {
                StudyCell(store: $0)
            }
        } else if vs.setting.studyViewMode == .edit {
            ForEachStore(
                self.store.scope(state: \.editWords, action: WordList.Action.editWords(id:action:))
            ) {
                EditCell(store: $0)
            }
        } else if vs.setting.studyViewMode == .selection {
            ForEachStore(
                self.store.scope(state: \.selectionWords, action: WordList.Action.selectionWords(id:action:))
            ) {
                SelectionCell(store: $0)
            }
        }
    }
}

원인 추정

위 코드에서 if 분기문은 각각의 Cell에 적용되어 있습니다. Cell 입장에서 생각을 해봅시다. Cell 입장에서 setting.studyViewMode는 State가 아닙니다. 따라서 값이 갱신이 되어도 Cell의 입장에서는 View를 리랜더링할 이유가 없습니다.

preview에서는 제대로 동작을 했었는데 말이죠… 하지만 preview와 simulator는 그 목적이 다릅니다. preview는 최대한 빨리 view를 업데이트해서 개발자에게 피드백을 주는 것을 목적으로 합니다. incremental updates이라는 기법을 사용한다고 합니다. (데이터가 변경된 부분만 업데이트하는 것) 반면에 simulator는 실제 기기에서 동작하는 것을 그대로 모방하는 것을 목적으로 합니다.

따라서 preview에서 시각적인 것 외의 다른 것들을 검증할 때는 신중할 필요가 있습니다. 실제 기기와 preview는 View 갱신 로직이 다르기 때문입니다.

개선한 코드

LazyVStack 자체를 if 분기문 안에 넣었습니다. 이렇게 하면 하나하나의 Cell을 갱신하는 것이 아니라 LazyVStack 자체를 통째로 갱신하므로 상술한 문제가 발생하지 않습니다.

ScrollView {
    if vs.setting.studyViewMode == .normal {
        LazyVStack(spacing: 32) {
            ForEachStore(
              self.store.scope(state: \.words, action: WordList.Action.word(id:action:))
            ) {
                StudyCell(store: $0)
            }
        }
    } else if vs.setting.studyViewMode == .edit {
        LazyVStack(spacing: 32) {
            ForEachStore(
                self.store.scope(state: \.editWords, action: WordList.Action.editWords(id:action:))
            ) {
                EditCell(store: $0)
            }
        }
    } else if vs.setting.studyViewMode == .selection {
        LazyVStack(spacing: 32) {
            ForEachStore(
                self.store.scope(state: \.selectionWords, action: WordList.Action.selectionWords(id:action:))
            ) {
                SelectionCell(store: $0)
            }
        }
    }
}
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글