जैसा कि निम्न एनिमेशन प्रदर्शित करता है, जब मैं सूची आइटम में से किसी एक को टैप करता हूं जिसे StreamBuilder() क्वेरी कर रहा है, तो यह आइटम डेटा को सही गहरे रंग के कंटेनर पर दिखाता है (यह हमेशा '_JsonQueryDocumentSnapshot' का उदाहरण होता है। / एम>)। लेकिन एक ही समय में प्रत्येक नल में, पूरी सूची अपने आप को ताज़ा कर रही है, जो कि बहुत लागत प्रभावी नहीं है, मेरा मानना ​​​​है।

मैं इस अवांछित रीफ़्रेश से कैसे बच सकता हूं? GetX राज्य प्रबंधन निर्भरता वाले उत्तरों का भी स्वागत है।

enter image description here

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'),
          ),
        ),
      ],
    );
  }
}
2
SLendeR 3 सितंबर 2021, 20:36

2 जवाब

सबसे बढ़िया उत्तर

मेरे लिए सबसे आसान उपाय यह होगा कि इसे केवल स्टेटलेस बनाया जाए और Getx वर्ग का उपयोग किया जाए।

class ScheduleController extends GetxController {
  var chosenData;

  void updateChosenData(var data) {
    chosenData = data;
    update();
  }
}

और आपका शेड्यूल.डार्ट इस तरह दिखेगा:

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
            ),
          ),
        ),
      ],
    );
  }
}

इस तरह listview.builder कभी भी पुनर्निर्माण नहीं करता है, केवल GetBuilder के अंदर सीधे टेक्स्ट विजेट को फिर से बनाया जाता है जब आप एक अलग ListTile का चयन करते हैं।

1
SLendeR 4 सितंबर 2021, 13:29

कॉल करना setState() फ्रेमवर्क को सूचित करता है कि शेड्यूल की स्थिति बदल गई है, जो विजेट के पुनर्निर्माण का कारण बनती है और इसलिए आपका StreamBuilder

आप अपने स्ट्रीम लॉजिक को विजेट ट्री के ऊपरी स्तर पर ले जा सकते हैं। इसलिए, setState(), StreamBuilder के पुनर्निर्माण को ट्रिगर नहीं करेगा।

class ParentWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: FirebaseFirestore.instance
          .collection('Schedule')
          .where(
            'date',
            isGreaterThan: DateTime.now().subtract(Duration(days: 1)),
          )
          .limit(10)
          .orderBy('date')
          .snapshots(),
      builder: (context, snapshot) {
        return Schedule(snapshot: snapshot); // Pass snapshot to Schedule
      },
    );
  }
}

दूसरा तरीका यह होगा कि Stream.listen को < में इस्तेमाल किया जाए a href="https://api.flutter.dev/flutter/widgets/State/initState.html" rel="nofollow noreferrer">initState() जिसे एक बार कॉल किया जाता है। इस तरह आपकी स्ट्रीम को हर बार setState() कॉल करने पर सब्सक्राइब नहीं किया जाएगा।

...

late StreamSubscription<QuerySnapshot> _subscription;

@override
void initState() {
  _subscription = _db
    .collection('Schedule')
    .where('date', isGreaterThan: _yesterday)
    .limit(10)
    .orderBy('date')
    .snapshots()
    .listen((QuerySnapshot querySnapshot) {
      setState(() {
        _querySnapshot = querySnapshot;
      });
    });

  super.didChangeDependencies();
}

@override
void dispose() {
  _subscription.cancel(); // Cancel the subscription
  super.dispose();
}

...
0
Stewie Griffin 3 सितंबर 2021, 19:46