Kodokon kodokon.com

संरचित स्टेट प्रबंधन: ChangeNotifier और Provider

लक्षित रीबिल्ड के लिए watch, read और select में महारत हासिल करते हुए ChangeNotifier और Provider के साथ एप्लिकेशन स्टेट साझा करें।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

जब तक स्टेट किसी एक स्क्रीन के साथ जीता और मरता है, तब तक setState काफ़ी है। जैसे ही डेटा साझा होता है - कार्ट, सेशन, प्राथमिकताएँ - उसे कंस्ट्रक्टर से कंस्ट्रक्टर तक नीचे पास करना अप्रबंधनीय हो जाता है। ChangeNotifier SDK का न्यूनतम ऑब्ज़र्वेबल प्रदान करता है; provider उसे ट्री में इंजेक्ट करता है और केवल सब्सक्राइब किए गए विजेट को रीबिल्ड करता है। Riverpod या Bloc की तुलना में, यह जोड़ी ऑडिट करने में सबसे आसान बनी रहती है: थोड़ा जादू, एक अकेली डिपेंडेंसी, एक ऐसा तंत्र जिसे आप एक वाक्य में समझा सकते हैं।

BASH
flutter pub add provider

एक अच्छी तरह से डिज़ाइन किया गया नोटिफायर एनकैप्सुलेट करता है: निजी फ़ील्ड, केवल-पठन गेटर, केवल उन मेथड के ज़रिए बदलाव जो notifyListeners() के साथ समाप्त होते हैं। यही अनुबंध इस बात की गारंटी देता है कि कोई भी स्टेट परिवर्तन UI से बच न पाए।

DART
import 'package:flutter/foundation.dart';

class CartModel extends ChangeNotifier {
  final List<String> _items = [];

  List<String> get items => List.unmodifiable(_items);

  int get count => _items.length;

  void add(String item) {
    _items.add(item);
    notifyListeners();
  }

  void remove(String item) {
    _items.remove(item);
    notifyListeners();
  }
}
निजी स्टेट, बाहर के लिए केवल-पठन, अधिसूचना।

तीन प्रवेश बिंदु, तीन उपयोग। context.watch<T>() विजेट को सब्सक्राइब करता है: यह हर notifyListeners पर रीबिल्ड होता है। context.read<T>() बिना सब्सक्राइब किए पढ़ता है: यह onPressed जैसे कॉलबैक के लिए उपकरण है। context.select<T, R>() केवल एक प्रोजेक्शन को सब्सक्राइब करता है: विजेट केवल तभी रीबिल्ड होता है जब वह सटीक वैल्यू बदलती है। सुनहरा नियम: watch और select केवल build में, read हैंडलर में - कभी उल्टा नहीं।

DART
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterModel extends ChangeNotifier {
  int _value = 0;

  int get value => _value;

  void increment() {
    _value++;
    notifyListeners();
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CounterModel(),
      child: const CounterApp(),
    ),
  );
}

class CounterApp extends StatelessWidget {
  const CounterApp({super.key});

  @override
  Widget build(BuildContext context) {
    final value = context.watch<CounterModel>().value;
    return MaterialApp(
      home: Scaffold(
        body: Center(child: Text('Count: $value')),
        floatingActionButton: FloatingActionButton(
          onPressed: () =>
              context.read<CounterModel>().increment(),
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}
पढ़ने के लिए build में watch, कार्य करने के लिए कॉलबैक में read।
DART
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CartModel extends ChangeNotifier {
  final List<String> _items = [];

  int get count => _items.length;
}

class CartBadge extends StatelessWidget {
  const CartBadge({super.key});

  @override
  Widget build(BuildContext context) {
    final count = context.select(
      (CartModel cart) => cart.count,
    );
    return Badge(
      label: Text('$count'),
      child: const Icon(Icons.shopping_cart),
    );
  }
}
CartBadge केवल तभी रीबिल्ड होता है जब count बदलता है।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. किसी onPressed के भीतर, बिना किसी अनावश्यक सब्सक्रिप्शन के आप cart.add(...) को कैसे ट्रिगर करते हैं?
    • context.watch<CartModel>().add(...)
    • context.read<CartModel>().add(...)
    • context.select((CartModel c) => c.add(...))
  2. notifyListeners() वास्तव में क्या ट्रिगर करता है?
    • केवल उन विजेट का रीबिल्ड जो बदले गए डेटा का उपयोग करते हैं।
    • एप्लिकेशन का एक संपूर्ण रीबिल्ड।
    • नोटिफायर को सब्सक्राइब किए गए सभी विजेट का रीबिल्ड, चाहे कोई भी डेटा बदला हो।
  3. _items को सीधे प्रकट करने के बजाय List.unmodifiable(_items) क्यों प्रकट करें?
    • सूची के पठन प्रदर्शन को बेहतर बनाने के लिए।
    • किसी बाहरी बदलाव को रोकने के लिए जो notifyListeners के बिना, और इसलिए बिना रीबिल्ड के, स्टेट बदल देता।
    • क्योंकि Provider परिवर्तनीय सूचियों को इंजेक्ट करने से इनकार करता है।