jh95
jh95

Reputation: 399

How can I use a variable set in one View in the PreviewProvider for that View?

I have a variable named homesList that I set in the completion handler of a function call to the server. However, homesList is not accessible in the PreviewProvider. How can I access homesList in the PreviewProvider?

struct HomeRow: View {
var home: Home
@State private var homesList: [Home]

var body: some View {
    HStack {
        Text(home.homeName)
        Spacer()
    }
    .onAppear {
        retrieveHomes(completionHandler: { (json) in
            self.homesList = json
        })
    }
  }
}


struct HomeRow_Previews: PreviewProvider {
  static var previews: some View {
    Group {
        HomeRow(home: homesList[0])
    }
    .previewLayout(.fixed(width: 300, height: 70))
  }
}

Upvotes: 1

Views: 571

Answers (1)

Asperi
Asperi

Reputation: 257779

Separating model management into view model and using dependency injection give possibility to mock view model for preview.

Here is a demo of possible approach. Tested with Xcode 12 / iOS 14

struct Home { // just replicated for test
    var homeName: String
}

class HomesViewModel: ObservableObject {
    @Published var homesList: [Home]

    init(homes: [Home] = []) {   // default container
        self.homesList = homes
    }

    func fetchHomes() {
        guard homesList.isEmpty else { return }

        retrieveHomes(completionHandler: { (json) in    // load if needed
            DispatchQueue.main.async {
                self.homesList = json   // should be set on main queue
            }
        })
    }
}

struct HomeRow: View {
    var home: Home
    @ObservedObject var vm: HomesViewModel

    var body: some View {
        HStack {
            Text(home.homeName)
            Spacer()
        }
        .onAppear {
            self.vm.fetchHomes()
        }
    }
}


struct HomeRow_Previews: PreviewProvider {
    static var previews: some View {

        // prepare mock model with predefined mock homes
        let mockModel = HomesViewModel(homes: [Home(homeName: "Mock1"), Home(homeName: "Mock2")])

        return Group {
            // inject test model via init
            HomeRow(home: mockModel.homesList[0], vm: mockModel)
        }
        .previewLayout(.fixed(width: 300, height: 70))
    }
}

Upvotes: 1

Related Questions