简体   繁体   中英

Error: The method 'data' isn't defined for the class 'Object?'

Error: The method 'data' isn't defined for the class 'Object?'.
 - 'Object' is from 'dart:core'.
Try correcting the name to the name of an existing method, or defining a method named 'data'.
                            Map _productMap = productSnap.data.data();      
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:your_store/screens/product_page.dart';
import 'package:your_store/services/firebase_services.dart';
import 'package:your_store/widgets/custom_action_bar.dart';

class SavedTab extends StatelessWidget {
  final FirebaseServices _firebaseServices = FirebaseServices();

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Stack(
        children: [
          FutureBuilder<QuerySnapshot>(
            future: _firebaseServices.usersRef
                .doc(_firebaseServices.getUserId())
                .collection("Saved")
                .get(),
            builder: (context, snapshot) {
              if (snapshot.hasError) {
                return Scaffold(
                  body: Center(
                    child: Text("Error: ${snapshot.error}"),
                  ),
                );
              }

              // Collection Data ready to display
              if (snapshot.connectionState == ConnectionState.done) {
                // Display the data inside a list view
                return ListView(
                  padding: EdgeInsets.only(
                    top: 108.0,
                    bottom: 12.0,
                  ),
                  children: snapshot.data!.docs.map((document) {
                    return GestureDetector(
                      onTap: () {
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => ProductPage(
                                productId: document.id,
                              ),
                            ));
                      },
                      child: FutureBuilder(
                        future:
                            _firebaseServices.productRef.doc(document.id).get(),
                        builder: (context, productSnap) {
                          if (productSnap.hasError) {
                            return Container(
                              child: Center(
                                child: Text("${productSnap.error}"),
                              ),
                            );
                          }

                          if (productSnap.connectionState ==
                              ConnectionState.done) {
                            Map _productMap = productSnap.data.data();

                            return Padding(
                              padding: const EdgeInsets.symmetric(
                                vertical: 16.0,
                                horizontal: 24.0,
                              ),
                              child: Row(
                                mainAxisAlignment: MainAxisAlignment.start,
                                children: [
                                  Container(
                                    width: 90,
                                    height: 90,
                                    child: ClipRRect(
                                      borderRadius: BorderRadius.circular(8.0),
                                      child: Image.network(
                                        "${_productMap['images'][0]}",
                                        fit: BoxFit.cover,
                                      ),
                                    ),
                                  ),
                                  Container(
                                    padding: EdgeInsets.only(
                                      left: 16.0,
                                    ),
                                    child: Column(
                                      mainAxisAlignment:
                                          MainAxisAlignment.start,
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        Text(
                                          "${_productMap['name']}",
                                          style: TextStyle(
                                              fontSize: 18.0,
                                              color: Colors.black,
                                              fontWeight: FontWeight.w600),
                                        ),
                                        Padding(
                                          padding: const EdgeInsets.symmetric(
                                            vertical: 4.0,
                                          ),
                                          child: Text(
                                            "\$${_productMap['price']}",
                                            style: TextStyle(
                                                fontSize: 16.0,
                                                color: Theme.of(context)
                                                    .accentColor,
                                                fontWeight: FontWeight.w600),
                                          ),
                                        ),
                                        Text(
                                          "Size - ${document['size']}",
                                          style: TextStyle(
                                              fontSize: 16.0,
                                              color: Colors.black,
                                              fontWeight: FontWeight.w600),
                                        ),
                                      ],
                                    ),
                                  ),
                                ],
                              ),
                            );
                          }

                          return Container(
                            child: Center(
                              child: CircularProgressIndicator(),
                            ),
                          );
                        },
                      ),
                    );
                  }).toList(),
                );
              }

              // Loading State
              return Scaffold(
                body: Center(
                  child: CircularProgressIndicator(),
                ),
              );
            },
          ),
          CustomActionBar(
            title: "Saved",
            hasBackArrow: false,
          ),
        ],
      ),
    );
  }
}

There are multiple problems in your code (taken from your GitHub repo.). I will try list all the problems here with some explanation about each. A common theme are a misunderstanding of using generics so I will recommend you to read about them:

https://dart.dev/guides/language/language-tour#generics

I will highly recommend you are trying to be as specific as possible with all your types in your code since a lot of the current behavior are making use of dynamic which is not really needed. By making the code more statically type safe, you can also get the compiler to find a lot of errors which is otherwise going to be runtime crashes.

The following found problems is not a full list since most of your problems has the same underlying problem as one of these.

Generic types has been removed

In firebase_services.dart you has this:

  final CollectionReference productRef =
      FirebaseFirestore.instance.collection("Products");

  final CollectionReference usersRef =
      FirebaseFirestore.instance.collection("Users");

This is not correct since you are removing the generic type from CollectionReference so it becomes CollectionReference<dynamic> . If you read the return type of .collection in both cases you will see the returned type is CollectionReference<Map<String, dynamic>> .

This is important since this type is used when calling methods on the CollectionReference object other places in your program.

So this should be changed to:

  final CollectionReference<Map<String, dynamic>> productRef =
      FirebaseFirestore.instance.collection("Products");

  final CollectionReference<Map<String, dynamic>> usersRef =
      FirebaseFirestore.instance.collection("Users");

Missing generic with use of FutureBuilder

In cart_page.dart you have a line 52 the following:

                      child: FutureBuilder(
                        future:
                            _firebaseServices.productRef.doc(document.id).get(),
                        builder: (context, productSnap) {

If you check the resolved type of productSnap you can see Dart thinks this has the type AsyncSnapshot<Object?> which is not that specific. If you look at the documentation for FutureBuilder it shows you should use this with a generic type which tells what type you expect the Future to return:

https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

So change the definition of FutureBuilder to:

child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(

Another example is in the same file at line 20 with:

          FutureBuilder<QuerySnapshot>(
            future: _firebaseServices.usersRef
                .doc(_firebaseServices.getUserId())
                .collection("Cart")
                .get(),
            builder: (context, snapshot) {

Here, you have QuerySnapshot but forgets that it also takes generic arguments. So based on the returned value from the future segment this should really be:

FutureBuilder<QuerySnapshot<Map<String, dynamic>>>(

Missing generic in variable declaration

With our more specific types in the code we come to this error (still in cart_page.dart ) which gives us an error:

                          if (productSnap.connectionState ==
                              ConnectionState.done) {
                            Map _productMap = productSnap.data.data();

A value of type 'Map<String, dynamic>?' can't be assigned to a variable of type 'Map<dynamic, dynamic>'.

The problem here is that by writing Map you are actually writing Map<dynamic, dynamic> which will remove important type information. I will recommend just using var or final and let Dart automatically assign the best possible type for the variable:

final _productMap = productSnap.data.data();

Missing handling of possible null value

Let's continue with the exact same line. Now we gets the following error:

The method 'data' can't be unconditionally invoked because the receiver can be 'null'.

The problem is that the data property can be null in case of an error has happen. I don't know how you want to handle this so for now, I am just going to ignore the problem and uses ! to force a runtime null-check to be added:

final _productMap = productSnap.data!.data();

But this is not enough since the output from data() can also be null which your code are not handling. Again, I don't know how you want to handle empty data so I am just ignoring the problem:

final _productMap = productSnap.data!.data()!;

Wrong value type when calling ProductSize constructor

Inside product_page.dart you have at line 114 the following:

                  ProductSize(
                    productSize: productSize,
                    onSelected: (size){
                      _selectedProductSize = size;
                    },
                  ),

Your ProductSize constructor is:

  final List? productSize;
  final String? onSelected;
  ProductSize({this.productSize, this.onSelected});

So you are trying to assign a method to onSelected which takes a String? as argument. I don't know what you are trying to do here but the current code does not make any sense.

builder: (context, snapshot) {
              if (snapshot.hasError) {
                return Scaffold(
                  body: Center(
                    child: Text("Error: ${snapshot.error}"),
                  ),
                );
              }

Convert the snapshot to AsyncSnapshot snapshot to solve this error. This works for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM