Avnish Nishad
Avnish Nishad

Reputation: 1852

ChangeNotifierProvider vs ChangeNotifierProvider.value

I am quite new to this framework and working on state management using provider package where I come across ChangeNotifierProvider and ChangeNotifierProvider.value, but I am unable to distinguish their use case.

I had used ChangeNotifierProvider in place of ChangeNotifierProvider.value, but it doesn't work as intended.

Upvotes: 49

Views: 31786

Answers (5)

Suragch
Suragch

Reputation: 511646

Let's take this in steps.

What is ChangeNotifier?

A class that extends ChangeNotifier can call notifyListeners() any time data in that class has been updated and you want to let a listener know about that update. This is often done in a view model to notify the UI to rebuild the layout based on the new data.

Here is an example:

class MyChangeNotifier extends ChangeNotifier {
  int _counter = 0;
  int get counter => _counter;

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

I wrote more about this in A beginner’s guide to architecting a Flutter app.

What is ChangeNotifierProvider?

ChangeNotifierProvider is one of many types of providers in the Provider package. If you already have a ChangeNotifier class (like the one above), then you can use ChangeNotifierProvider to provide it to the place you need it in the UI layout.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyChangeNotifier>(        // define it
      create: (context) => MyChangeNotifier(),              // create it
      child: MaterialApp(
        ...

          child: Consumer<MyChangeNotifier>(                // get it
            builder: (context, myChangeNotifier, child) {
              ...
                  myChangeNotifier.increment();             // use it

Note in particular that a new instance of the MyChangeNotifier class was created in this line:

create: (context) => MyChangeNotifier(),

This is done one time when the widget is first built, and not on subsequent rebuilds.

What is ChangeNotifierProvider.value for then?

Use ChangeNotifierProvider.value if you have already created an instance of the ChangeNotifier class. This type of situation might happen if you had initialized your ChangeNotifier class in the initState() method of your StatefulWidget's State class.

In that case, you wouldn't want to create a whole new instance of your ChangeNotifier because you would be wasting any initialization work that you had already done. Using the ChangeNotifierProvider.value constructor allows you to provide your pre-created ChangeNotifier value.

class _MyWidgeState extends State<MyWidge> {

  MyChangeNotifier myChangeNotifier;

  @override
  void initState() {
    myChangeNotifier = MyChangeNotifier();
    myChangeNotifier.doSomeInitializationWork();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyChangeNotifier>.value(
      value: myChangeNotifier,                           // <-- important part
      child: ... 

Take special note that there isn't a create parameter here, but a value parameter. That's where you pass in your ChangeNotifier class instance. Again, don't try to create a new instance there.

You can also find the usage of ChangeNotifierProvider and ChangeNotifierProvider.value described in the official docs: https://pub.dev/packages/provider#exposing-a-value

Upvotes: 100

elopezp
elopezp

Reputation: 627

Basically the ChangeNotifierProvider with builder(Provider v3) or create(Provider v4) parameter is a disposing provider, this provider owns the state source and manages its lifetime. The value provider only references the state source but does not manage its lifetime. In disposing providers, the builder or create parameter provides a function for creating the state source. In value providers there is a value parameter which takes a reference to the state source and you are responsible for creating and disposing the state source as needed.

Upvotes: 1

AliAzad
AliAzad

Reputation: 263

Is an important difference between ChangeNotifierProvider.value and with the create function. When you're using Provider in a single list or grid item, Flatter removes items when they leave the screen and re adds them when they reentered the screen in such situations what actually happens is that the widget itself is reused by Flutter and just the data that's attached to it changes. So Flatter recycles the same widget it doesn't destroy it and recreate it. when we are using Provider with the create function.

ChangeNotifierProvider(
  create: (_) => new MyChangeNotifier(),
  child: ...
)

☝☝☝ here which is content changes over time and our provider won't pick us up.

In a single list or grid item, we should use Provider dot value.

ChangeNotifierProvider.value(
  value: new MyChangeNotifier(),
  child: ...
)

Upvotes: 3

Zeeshan Ansari
Zeeshan Ansari

Reputation: 1483

ValueNotifier and ChangeNotifier are closely related.

In fact, ValueNotifier is a subclass of ChangeNotifier that implements ValueListenable.

This is the implementation of ValueNotifier in the Flutter SDK:

/// A [ChangeNotifier] that holds a single value.
///
/// When [value] is replaced with something that is not equal to the old
/// value as evaluated by the equality operator ==, this class notifies its
/// listeners.
class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
  /// Creates a [ChangeNotifier] that wraps this value.
  ValueNotifier(this._value);

  /// The current value stored in this notifier.
  ///
  /// When the value is replaced with something that is not equal to the old
  /// value as evaluated by the equality operator ==, this class notifies its
  /// listeners.
  @override
  T get value => _value;
  T _value;
  set value(T newValue) {
    if (_value == newValue)
      return;
    _value = newValue;
    notifyListeners();
  }

  @override
  String toString() => '${describeIdentity(this)}($value)';
}

So, when should we use ValueNotifier vs ChangeNotifier?

Use ValueNotifier if you need widgets to rebuild when a simple value changes. Use ChangeNotifier if you want more control on when notifyListeners() is called.

Upvotes: 5

timr
timr

Reputation: 6962

Does the official documentation help?

DO use ChangeNotifierProvider.value to provider an existing ChangeNotifier:

ChangeNotifierProvider.value(
  value: variable,
  child: ...
)

DON'T reuse an existing ChangeNotifier using the default constructor.

ChangeNotifierProvider(
  builder: (_) => variable,   
  child: ... 
)

Also check out this Github issue from the author about this.

Upvotes: 9

Related Questions