flutter_bloc - как хранить переменные в памяти между экранами - PullRequest
1 голос
/ 09 ноября 2019

Я использую flutter_bloc для обработки состояния в моем приложении Flutter. Я использую Firestore в качестве хранилища.

Мой вопрос:

  1. Каков наилучший способ хранения временных переменных и обеспечения их доступности на всех экранах?
  2. Предполагается ли, что, если я хочу создавать запросы Firestore с вложенными коллекциями, мне нужно передать идентификаторы документов через блок и репозиторий для создания запросов?

Как и в моем случае, мне нужно хранить идентификаторы, чтобы иметь возможность создавать запросы firestore с вложенными коллекциями в документах.

У меня есть следующая структура в firestore:

school (document)
  - courses (collection)
    - course1 (document)
    - course2 (document)
    - ...
      - sections (collection)
        - ...

Запросы:

Чтобы получить курсы:

Firestore.instance
  .collection('schools')
  .document('<school id>')
  .collection("courses")
  .snapshots();

Чтобы получить разделы для курса:

Firestore.instance
  .collection('schools')
  .document('<school id>')
  .collection('courses')
  .document('<course id>')
  .collection('sections')
  .snapshots();

Так что мне нужно как-то сохранить "идентификатор школы" и ""идентификатор курса" и передайте их в блок и хранилище для создания запроса к хранилищу.

В данный момент функция моего блока, которая загружает школу, загрузит ее из хранилища и затем сохранит ее, сериализовав в shared_preferences.

Функция, которая читает школу, будет читать ее из shared_preferences, а не из firestore после этого. Таким образом, я могу получить доступ к shared_preferences с другого экрана, когда мне нужны данные. Но почему-то это выглядит немного грязно. Я посмотрел на hydrated_bloc, который в основном делает то же самое, так что я мог бы использовать это, но он все еще чувствует себя грязно, передавая переменные через блок и репозиторий для построения запроса.

Я новичоккогда дело доходит до создания хорошей архитектуры с помощью блока, и я бы предпочел построить что-то правильное с самого начала.

Кто-нибудь знает лучший способ сделать это?

Вот мой класс репозитория,Как видите, мне нужно проанализировать идентификатор школьного документа в репозитории Firebase. На данный момент это жестко закодировано.

class FirebaseCourseRepository implements CourseRepository {
  final courseCollection = Firestore.instance
    .collection('school')
    .document("3kRHuyk20UggHwm4wrUI") // this is where I need to pass the doc id from the bloc to.
    .collection("course");

  @override
  Stream<List<Course>> courses() {
    return courseCollection.snapshots()
      .map((snapshot) {
      return snapshot.documents
          .map((doc) => Course.fromEntity(CourseEntity.fromSnapshot(doc)))
          .toList();
    });
  }

  @override
  Future<void> addCourse(Course course) {
    return courseCollection.add(course.toEntity().toDocument());
  }

  @override
  Future<void> updateCourse(Course updatedCourse) {
    return courseCollection
        .document(updatedCourse.id)
        .updateData(updatedCourse.toEntity().toDocument());
  }

  @override
  Future<void> deleteCourse(Course course) async {
    return courseCollection.document(course.id).delete();
  }  
}

А вот и блок. Я действительно не знаю, как я могу передать идентификатор документа в хранилище только один раз.

class CourseBloc extends Bloc<CourseEvent, CourseState> {
  final CourseRepository _courseRepository;
  StreamSubscription _courseSubscription;

  // Repository is injected through constructor, so that it can
  // be easily tested.
  CourseBloc({@required CourseRepository courseRepository})
      : assert(courseRepository != null),
        _courseRepository = courseRepository;

  @override
  get initialState => CourseInitState();

  @override
  Stream<CourseState> mapEventToState(CourseEvent event) async* {
    if(event is LoadCoursesEvent) {
      yield* _mapLoadCoursesToState(event);
    } else if(event is CoursesLoadedEvent) {
      yield* _mapCoursesLoadedToState(event);
    } else if(event is AddCourseEvent) {
      yield* _mapAddCourseToState(event);
    } else if(event is UpdateCourseEvent) {
      yield* _mapUpdateCourseToState(event);
    } else if(event is DeleteCourseEvent) {
      yield* _mapDeleteCourseToState(event);
    }
  }

  // Load all courses
  Stream<CourseState> _mapLoadCoursesToState(LoadCoursesEvent event) async* {
    yield CoursesLoadingState();
    _courseSubscription?.cancel();
    _courseSubscription = _courseRepository.courses().listen(
      (courses) {
        dispatch(
          CoursesLoadedEvent(courses),
        );
      },
    );
  }

  Stream<CourseState> _mapCoursesLoadedToState(CoursesLoadedEvent event) async* {
    yield CoursesLoadedState(event.courses);
  }

  Stream<CourseState> _mapAddCourseToState(AddCourseEvent event) async* {
    _courseRepository.addCourse(event.course);
  }

  Stream<CourseState> _mapUpdateCourseToState(UpdateCourseEvent event) async* {
    _courseRepository.updateCourse(event.updatedCourse);
  }  

  Stream<CourseState> _mapDeleteCourseToState(DeleteCourseEvent event) async* {
    _courseRepository.deleteCourse(event.course);
  }  

  @override
  void dispose() {
    _courseSubscription?.cancel();
    super.dispose();
  }
}
...