I'm trying to fetch documents from my firebase DB and use them to create a social media feed. Here I'm trying to get the length of the fetched collection but I cannot manage to call the variable. Any help would be appreciated. Example code
class LoadDataFromFirestore extends StatefulWidget {
@override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
@override
void initState() {
super.initState();
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection('fish');
Future<void> getData() async {
// Get docs from collection reference
QuerySnapshot querySnapshot = await _collectionRef.get();
// Get data from docs and convert map to List
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
}
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: querySnapshot.docs.length,
itemBuilder: (BuildContext context, int index) {
return _postView();
},
),
);
}
}
CodePudding user response:
First of all it is not ok to call future
function in initstate
, you need to use FutureBuilder
like this:
class LoadDataFromFirestore extends StatefulWidget {
@override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
late CollectionReference _collectionRef;
@override
void initState() {
super.initState();
_collectionRef = FirebaseFirestore.instance.collection('fish');
}
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<QuerySnapshot>(
future: _collectionRef.get(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
QuerySnapshot? querySnapshot = snapshot.data;
return ListView.builder(
itemCount: querySnapshot?.docs?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
var data = querySnapshot?.docs?[index].data();
print("data = $data");
return _postView();
},
);
}
}
},
),
);
}
}
inside listview's builder you can use data
to parse your data and use it.
CodePudding user response:
You can use the querySnapshot data in a listview builder by mapping the querySnapshot data to a list of widgets and then passing that list to the ListView.builder constructor.
Here is an example:
// Get the query snapshot
var querySnapshot = await Firestore.instance.collection('users').getDocuments();
// Map the query snapshot data to a list of widgets
var users = querySnapshot.documents.map((document) => UserWidget(document)).toList();
// Use the list of widgets in the ListView.builder constructor
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return users[index];
},
);
In this example, the UserWidget is a custom widget that takes in a document from the query snapshot and returns a widget that displays the data in the document. You can modify this example to fit your specific needs.
CodePudding user response:
One way to make the querySnapshot variable accessible within the itemBuilder function is to move the getData() function to the build() method, and use the await keyword to wait for the data to be fetched before building the ListView. This will ensure that the querySnapshot variable is available when the itemBuilder function is called:
class LoadDataFromFirestore extends StatefulWidget {
@override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
QuerySnapshot querySnapshot;
@override
void initState() {
super.initState();
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection('fish');
getData(_collectionRef);
}
Future<void> getData(CollectionReference _collectionRef) async {
// Get docs from collection reference
querySnapshot = await _collectionRef.get();
// Get data from docs and convert map to List
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: querySnapshot?.docs?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
return _postView();
},
),
);
}
}
CodePudding user response:
You can use FutureBuilder like this:
class LoadDataFromFirestore extends StatefulWidget {
const LoadDataFromFirestore({super.key});
@override
State<LoadDataFromFirestore> createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
//TODO change Map<String, dynamic> with your data type with fromJson for example
Future<List<Map<String, dynamic>>> _getData() async {
final querySnapshot = await FirebaseFirestore.instance.collection('fish').get();
return querySnapshot.docs.map((doc) => doc.data()).toList();
}
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Map<String, dynamic>>>(
future: _getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return _postView(/* Ithink you have to pass here your item like snapshot.data[index]*/);
},
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
}