Search code examples
flutterdartflutter-dependencies

Dart 3 get doc in collection across a routing system


I'm trying to get the return of a Future<> function across my routing system.

I got an error:

The non-nullable local variable 'page' must be assigned before it can be used

raised by the return of my class RouteGenerator.

My RouteGenerator.dart :

import 'package:chope_ton_diplome/services/CommonService.dart';
import 'package:flutter/material.dart';

class RouteGenerator {
  static Route generate(RouteSettings s) {
    Widget page;
    CommonService commonService = CommonService();

    switch (s.name) {
      case RouteConsts.termsScreen:
        ArgumentsAuth args = s.arguments as ArgumentsAuth;
        commonService.terms.then((terms) =>
        page = TermsScreen(email: args.email, terms: terms)
        );
        break;
      default:
        page = const Center(
          child: Text('La route est inaccessible'),
        );
        break;
    }

    return MaterialPageRoute(builder: (context) => page);
  }
}

For information, this is my CommonService:

import 'package:cloud_firestore/cloud_firestore.dart';

class CommonService {
  final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;

  Future<String> get terms async {
    String content = '';
    DocumentReference documentReference = firebaseFirestore.collection('commons').doc('terms');
    content = (await documentReference.get()).get('content');
    return content;
  }
}

Define a page call my widget, so I'm blocked.

Help please. Thanks for your time.


Solution

  • Your generate() method is synchronous so it will execute all the way down to the return statement that's using the page local variable. Continuation functions passed to then() will only execute after generate() has completed.

    In the switch statement, page is definitely assigned in the default case. But not in the other case where page will only be assigned a value when the function passed to then() executes (after the future commonService.terms completes -- even if the future has completed already). Since that will not happen before return is reached, in that case, page remains unassigned.

    You can work around this by assigning page with a FutureBuilder<T> based on the commonService.terms future. When this future complete, the builder should return the expected TermsScreen. In the meantime, it should provide another Widget, eg a CircularProgressIndicator.

       case RouteConsts.termsScreen:
          ArgumentsAuth args = s.arguments as ArgumentsAuth;
          page = FutureBuilder<String>(
             future: commonService.terms,
             builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
                if (snapshot.hasData) {
                   return TermsScreen(email: args.email, terms: snapshot.data!);
                } else {
                   return /* some widget shown until terms completes */;
                }
             }
          );
          break;