Search code examples
flutterdartflutter-provider

What is best practise with flutter provider to lazy load data


So when using provider with flutter, the main problem is that if want to specify the provider where its descendants need its value and its good until you don't use navigation if we use navigation then we have to use builder to provide new context so for most people provide all provider before material app in widget hierarchy but the problem with that, suppose i want to load a data which will load on the second screen so what i m suppose to put in initial model class because i don't think providing null values is a good way.

So my question is what is the best to lazy load data without using null or default empty values.

see below code for some context to my problem.

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    const title = 'GPA Calculator';
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => StudentManager()),
        ChangeNotifierProvider(create: (context) => StudentCourseManager()),
      ],
      child: MaterialApp(
        title: title,
        home: const HomeScreen(title: title),
      ),
    );
  }
}

class StudentManager extends ChangeNotifier {
  List<Student> _list = [];

  List<Student> get list => _list;

  void add(Student student) {
    _list.add(student);
    notifyListeners();
  }

  void remove(int index) {
    _list.removeAt(index);
    notifyListeners();
  }

  void update(
    int index,
    Student student,
  ) {
    _list[index] = student;
    notifyListeners();
  }
}

class StudentCourseManager extends ChangeNotifier {
  late int studentIndex;
  late StudentManager studentManager;

  StudentCourseManager({
    required this.studentIndex,
    required this.studentManager,
  });

  Student? get student => studentManager.list[studentIndex];

  List<StudentCourse> get list => student != null ? student!.courseList : [];

  void add(StudentCourse studentCourse) {
    student!.addCourse(studentCourse);
    studentManager.update(studentIndex, student!);
    notifyListeners();
  }

  void delete(int index) {
    student!.deleteCourse(index);
    studentManager.update(studentIndex, student!);
    notifyListeners();
  }

  void update(
    int index,
    StudentCourse studentCourse,
  ) {
    student!.updateCourse(index, studentCourse);
    studentManager.update(studentIndex, student!);
    notifyListeners();
  }
}

Solution

  • According to @Nico Spencer comment, i tried ChangeNotifierProxyProvider and i found it is improvement to my old way because its simply my code and also auto-update provider here is the code that i changed to.

    //...
    providers: [
            ChangeNotifierProvider<StudentManager>(
              create: (context) => StudentManager(),
            ),
            ChangeNotifierProxyProvider<StudentManager, StudentCourseManager>(
              create: (context) => StudentCourseManager(),
              update: (context, result, previous) {
                return previous!..student = result.currentStudent;
              },
            ),
          ],
    
    class StudentCourseManager extends ChangeNotifier {
      late Student student;
    
      List<StudentCourse> get list => student.courseList;
    
      void add(StudentCourse studentCourse) {
        student.addCourse(studentCourse);
        notifyListeners();
      }
    
      void delete(int index) {
        student.deleteCourse(index);
        notifyListeners();
      }
    
      void update(
        int index,
        StudentCourse studentCourse,
      ) {
        student.updateCourse(index, studentCourse);
        notifyListeners();
      }
    }
    
    
    // ...
    return StudentTile(
              student: student,
              onDelete: () => studentManager.remove(index),
              onTap: () {
                studentManager.currentStudent = student;
    
                Navigator.push<void>(
                  context,
                  MaterialPageRoute(builder: (context) => const CoursesScreen()),
                );
              },