Avoid ListView's unwanted refresh
241
To me the easiest solution would be just make it stateless and use a Getx
class.
class ScheduleController extends GetxController {
var chosenData;
void updateChosenData(var data) {
chosenData = data;
update();
}
}
And your Schedule.dart would look like this:
class Schedule extends StatelessWidget {
final FirebaseFirestore _db = FirebaseFirestore.instance;
final DateTime _yesterday = DateTime.now().subtract(Duration(days: 1));
@override
Widget build(BuildContext context) {
final controller = Get.put(ScheduleController());
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: _db
.collection('Schedule')
.where('date', isGreaterThan: _yesterday)
.limit(10)
.orderBy('date')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
var data = snapshot.data!.docs[index];
return ListTile(
leading: Icon(Icons.person),
title: Text(data['project'],
style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(data['parkour']),
onTap: () => controller.updateChosenData(data), // calls method from GetX class
);
},
);
} else {
return Center(child: CupertinoActivityIndicator());
}
},
),
),
VerticalDivider(),
Expanded(
child: Container(
alignment: Alignment.center,
color: Colors.black26,
child: GetBuilder<ScheduleController>(
builder: (controller) => Text('${controller.chosenData}'), // only this rebuilds
),
),
),
],
);
}
}
This way the listview.builder
never rebuilds, only the Text widget directly inside the GetBuilder
gets rebuilt when you selected a different ListTile
.
Author by
SLendeR
Updated on January 01, 2023Comments
-
SLendeR over 1 year
As the following animation displays, when I tap one of the list items that StreamBuilder() is querying, it shows the items data on the right darker container (it's always Instance of '_JsonQueryDocumentSnapshot'). But at the same time in each tap, the whole list is refreshing itself, which is not very cost-effective I believe.
How can I avoid this unwanted refresh? Answers with GetX state management dependency are also welcome.
class Schedule extends StatefulWidget { @override _ScheduleState createState() => _ScheduleState(); } class _ScheduleState extends State<Schedule> { final FirebaseFirestore _db = FirebaseFirestore.instance; final DateTime _yesterday = DateTime.now().subtract(Duration(days: 1)); var _chosenData; @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: StreamBuilder<QuerySnapshot>( stream: _db.collection('Schedule').where('date', isGreaterThan: _yesterday).limit(10).orderBy('date').snapshots(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.active) { return ListView.builder( itemCount: snapshot.data!.docs.length, itemBuilder: (context, index) { var data = snapshot.data!.docs[index]; return ListTile( leading: Icon(Icons.person), title: Text(data['project'], style: TextStyle(fontWeight: FontWeight.bold)), subtitle: Text(data['parkour']), onTap: () { setState(() {_chosenData = data;}); }, ); }, ); } else { return Center(child: CupertinoActivityIndicator()); } }, ), ), VerticalDivider(), Expanded( child: Container( alignment: Alignment.center, color: Colors.black26, child: Text('$_chosenData'), ), ), ], ); } }