Issue #468

From onAppeear

Adds an action to perform when the view appears.

In theory, this should be triggered every time this view appears. But in practice, it is only called when it is pushed on navigation stack, not when we return to it.

So if user goes to a bookmark in a bookmark list, unbookmark an item and go back to the bookmark list, onAppear is not called again and the list is not updated.

import SwiftUI

struct BookmarksView: View {
    let service: Service
    @State var items: [AnyItem]
    @EnvironmentObject var storeContainer: StoreContainer

    var body: some View {
        List(items)  { item in
            makeItemRow(item: item)
                .padding([.top, .bottom], 4)
        }
        .onAppear(perform: {
            self.items = storeContainer.bookmarks(service: service).map({ AnyItem(item: $0) })
        })
    }
}

So instead of relying on UI state, we should rely on data state, by listening to onReceive and update our local @State

struct BookmarksView: View {
    let service: Service
    @State var items: [AnyItem]
    @EnvironmentObject var storeContainer: StoreContainer

    var body: some View {
        List(items)  { item in
            makeItemRow(item: item)
                .padding([.top, .bottom], 4)
        }
        .onAppear(perform: {
            self.reload()
        })
        .onReceive(storeContainer.objectWillChange, perform: { _ in
            self.reload()
        })
    }

    private func reload() {
        self.items = storeContainer.bookmarks(service: service).map({ AnyItem(item: $0) })
    }
}

Inside our ObservableObject, we need to trigger changes notification

final class StoreContainer: ObservableObject {
    let objectWillChange = PassthroughSubject<(), Never>()

    func bookmark(item: ItemProtocol) {
        defer {
            objectWillChange.send(())
        }        
    }

    func unbookmark(item: ItemProtocol) {
        defer {
            objectWillChange.send(())
        }
    }
}

Updated at 2020-10-03 10:43:47