Network request in each item contained in a List not displaying data

106 views Asked by At

I am fetching data within a MovieItem component. When I just display one MovieItem this works correctly. However when I move this card into a List the data isn't fetched correctly and nothing is displayed.

My code looks something like this

MovieModel

class MovieModel: ObservableObject {
   var movie: Movie

   fetchMovie(movieId) {
     ...request stuff from core data...
     self.movie = movie
   }
}

ListView

struct ListView: View {
   @ObservedObject var movies: [Movie(name: "Titanic", id: 1)]

   var body: some View {

      List {
         ForEach(movies) { movie in
            MovieItem(movie: movie)
         }
      }
   }
}

MovieItem

struct MovieItem: View {
    @ObservedObject var movieModel: MovieModel
    var movie: Movie

    var body: some View {
      Text(movie.name)
    }
    .onAppear {
       movieModel.fetchMovie(movie)
    }
}

Is it obvious to anyone what's wrong and the approach to take to get this to work?

1

There are 1 answers

0
workingdog support Ukraine On

Try this structure, using one class MovieModel: ObservableObject and passing this model to other views using .environmentObject(movieModel).

See this link monitoring data, it gives you some good examples of how to manage data in your app.

struct ContentView: View {
    var body: some View {
        ListView()
    }
}

class MovieModel: ObservableObject {
    @Published var movies: [Movie] = [Movie(id: 1, name: "Titanic")]
    
    func fetchMovie(id: Int) {
        //...request
        // for testing
        if let index = movies.firstIndex(where: {$0.id == id}) {
            movies[index].name = movies[index].name + " II"
        }
    }
    
    func fetchAllMovies() {
        // for testing
        movies = [Movie(id: 1, name: "Titanic"), Movie(id: 2, name: "Mickey Mouse")]
    }
}

struct Movie: Identifiable {
    let id: Int
    var name: String
    //....
}

struct ListView: View {
    @StateObject var movieModel = MovieModel()
    
    var body: some View {
        List {
            ForEach(movieModel.movies) { movie in
                MovieItem(movie: movie)
            }
        }
        .onAppear {
            movieModel.fetchAllMovies()
        }
        .environmentObject(movieModel)
    }
}

struct MovieItem: View {
    @EnvironmentObject var movieModel: MovieModel
    var movie: Movie
    
    var body: some View {
        Text(movie.name)
            .onAppear {
                movieModel.fetchMovie(id: movie.id)
            }
    }
}

If you plan to use ios17, then have a look at this link Managing model data in your app for how to manage data in your app.