flutterdartriverpoddart-async

Using FutureBuilder in ConsumerStatefulWidget class causes error


I am trying to use a FutureBuilder with a ListView to display a list of documents from a Firestore db. I am getting errors saying the future: is not defined and the builder: is not defined. I also get an error at the < where I am trying to set the type for the Future builder. That error code is: The operator '<' isn't defined for the type 'Type'.

Here is my code:

class CompanyDashboardScreen extends ConsumerStatefulWidget {
  static const String id = 'user_dashboard_screen';

  const CompanyDashboardScreen({super.key});

  @override
  ConsumerState<CompanyDashboardScreen> createState() =>
      _CompanyDashboardScreenState();
}

class _CompanyDashboardScreenState
    extends ConsumerState<CompanyDashboardScreen> {
  bool showSpinner = false;

  late List<Map<String, dynamic>> itemsTrxn;
  bool isLoaded = false;

  Future<List<Map<String, dynamic>>> _getTrxnData() async {
    var collectionTrxn = FirebaseFirestore.instance
        .collection('company')
        .doc(ref.read(globalsNotifierProvider).companyId)
        .collection('trxns');

    List<Map<String, dynamic>> tempList = [];
    // ignore: unused_local_variable
    var dataTrxn = await collectionTrxn.get();

    dataTrxn.docs.forEach((element) {
      tempList.add(element.data());
    });

    setState(() {
      itemsTrxn = tempList;
      isLoaded = true;
    });

    return tempList;
  }

  @override
  void setState(VoidCallback fn) {
    _getTrxnData();
    super.setState(fn);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: CustomAppBar(),
        drawer: Drawer(
          child: ListView(
            children: <Widget>[
              ListTile(
                title: const Text("User Profile"),
                onTap: () {
                  MainScreen.of(context)
                      ?.setIndex(3); // Added this for BottomNavigationBar sync
                  Navigator.of(context).push(MaterialPageRoute(
                      builder: (context) => const UserProfileScreen()));
                },
              ),
            ],
          ),
        ),
        body: SafeArea(
          child: FutureBuilder <   <<< ERROR
              Map<String, dynamic>(
    ERROR >>>   future: FirebaseFirestore.instance
                    .collection('company')
                    .doc(ref.read(globalsNotifierProvider).companyId)
                    .collection('trxns')
                    .get(),
   ERROR >>>    builder: isLoaded
                    ? ListView.builder(
                        itemCount: itemsTrxn.length,
                        itemBuilder: (context, index) {
                          //_getTrxnData(); // Get the list of trxns

                          return Padding(
                            padding: cont EdgeInsets.all(8.0),
                            child: ListTile(
                              isThreeLine: true,
                              title: Row(
                                children: [
                                  Text(
                                    'Client: ${itemsTrxn[index]['clientFName'] ?? 'n/a'} ${itemsTrxn[index]['clientLName'] ?? 'n/a'}',
                                    style: const TextStyle(
                                        fontWeight: FontWeight.w900,
                                        color: Colors.blueAccent),
                                  ),
                                ],
                              ),
                              subtitle: Text.rich(
                                TextSpan(
                                  text:
                                      '${itemsTrxn[index]['propertyAddress'] ?? 'n/a'}, '
                                      '${itemsTrxn[index]['propertyCity'] ?? 'n/a'}, '
                                      '${itemsTrxn[index]['propertyState'] ?? 'n/a'}',
                                  children: <TextSpan>[
                                    TextSpan(
                                      text:
                                          '\nPrice: ${itemsTrxn[index]['contractPrice'] == null ? 'n/a' : NumberFormat.simpleCurrency().format(itemsTrxn[index]['contractPrice'])}\nStatus: ${itemsTrxn[index]['trxnStatus'] ?? 'n/a'}',
                                      style: const TextStyle(
                                          fontWeight: FontWeight.w900,
                                          color: Colors.blueGrey),
                                    )
                                  ],
                                ),
                              ),
                              trailing: Text(
                                  'MLS#: ${itemsTrxn[index]['mlsNumber'] ?? 'n/a'}\n${itemsTrxn[index]['clientType']}'),
                              onTap: () {
                                //MainScreen.of(context)?.setIndex(2);  // Added this for BottomNavigationBar sync
                                ref
                                    .read(globalsNotifierProvider.notifier)
                                    .updatenewTrxn(false);
                                ref
                                    .read(globalsNotifierProvider.notifier)
                                    .updatecurrentTrxnId(
                                        itemsTrxn[index]['trxnId']);
                                Navigator.of(context).push(MaterialPageRoute(
                                    builder: (context) =>
                                        TransactionDetailScreen(
                                            itemsTrxn[index]['trxnId'])));
                              },
                            ),
                          );
                        },
                      )
                    : const Text('No Date'),
              ),
        ),
      ),
    );
  }
}

What am I doing wrong to get these errors and how do I fix this? Thanks


Solution

  • Error 1:

    You missed a >

    Your code

    FutureBuilder<Map<String, dynamic>(...)
    

    Fixed code

    FutureBuilder<Map<String, dynamic>>(...)
    

    Error 2: builder is not just a widget, is a callback that returns a widget and is of type (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) => myWidget()

    builder: (context, snapshot) {
       return isLoaded ? ListView.builder(....) : const Text('No Date');
    }
    

    And as a side note, if you're already loading outside of the future builder there is no need to use that

    PS2: Don't override setState and a put a future callback _getTrxnData() inside, it will make a recursion because _getTrxnData uses setState inside, which will call _getTrxnData again and so on. Use Riverpod to make the computation inside the provider