provider 4.1.3

  • Readme
  • Changelog
  • Example
  • Installing
  • 100

English | Português

Black Lives Matter. Support the Equal Justice Initiative. #

Build Status pub package codecov Gitter

A wrapper around InheritedWidget to make them easier to use and more reusable.

By using provider instead of manually writing InheritedWidget, you get:

  • simplified allocation/disposal of resources
  • lazy-loading
  • a largely reduced boilerplate over making a new class every time
  • devtools friendly
  • a common way to consume these InheritedWidgets (See Provider.of/Consumer/Selector)
  • increased scalability for classes with a listening mechanism that grows exponentially in complexity (such as ChangeNotifier, which is O(N²) for dispatching notifications).

To read more about provider, see its documentation.

See also:

Migration from v3.x.0 to v4.0.0 #

  • The parameters builder and initialBuilder of providers are removed.

    • initialBuilder should be replaced by create.
    • builder of "proxy" providers should be replaced by update
    • builder of classical providers should be replaced by create.
  • The new create/update callbacks are lazy-loaded, which means they are called the first time the value is read instead of the first time the provider is created.

    If this is undesired, you can disable lazy-loading by passing lazy: false to the provider of your choice:

    FutureProvider(
      create: (_) async => doSomeHttpRequest(),
      lazy: false,
      child: ...
    )
    
  • ProviderNotFoundError is renamed to ProviderNotFoundException.

  • The SingleChildCloneableWidget interface is removed and replaced by a new kind of widget SingleChildWidget.

    See this issue for details on how to migrate.

  • Selector now deeply compares the previous and new values if they are collections.

    If this is undesired, you can revert to the old behavior by passing a shouldRebuild parameter to Selector:

    Selector<Selected, Consumed>(
      shouldRebuild: (previous, next) => previous == next,
      builder: ...,
    )
    
  • DelegateWidget and its family is removed. Instead, for custom providers, directly subclass InheritedProvider or an existing provider.

Usage #

Exposing a value #

Exposing a new object instance

Providers allow to not only expose a value, but also create/listen/dispose it.

To expose a newly created object, use the default constructor of a provider. Do not use the .value constructor if you want to create an object, or you may otherwise have undesired side-effects.

See this stackoverflow answer which explains in further details why using the .value constructor to create values is undesired.

  • DO create a new object inside create.
Provider(
  create: (_) => MyModel(),
  child: ...
)
  • DON'T use Provider.value to create your object.
ChangeNotifierProvider.value(
  value: MyModel(),
  child: ...
)
  • DON'T create your object from variables that can change over the time.

    In such a situation, your object would never be updated when the value changes.

int count;

Provider(
  create: (_) => MyModel(count),
  child: ...
)

If you want to pass variables that can change over time to your object, consider using ProxyProvider:

int count;

ProxyProvider0(
  update: (_, __) => MyModel(count),
  child: ...
)

NOTE:

When using the create/update callback of a provider, it is worth noting that this callback is called lazily by default.

What this means is, until the value is requested at least once, the create/update callbacks won't be called.

This behavior can be disabled if you want to pre-compute some logic, using the lazy parameter:

MyProvider(
  create: (_) => Something(),
  lazy: false,
)

Reusing an existing object instance:

If you already have an object instance and want to expose it, you should use the .value constructor of a provider.

Failing to do so may call the dispose method of your object when it is still in use.

  • DO use ChangeNotifierProvider.value to provide an existing ChangeNotifier.
MyChangeNotifier variable;

ChangeNotifierProvider.value(
  value: variable,
  child: ...
)
  • DON'T reuse an existing ChangeNotifier using the default constructor
MyChangeNotifier variable;

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

Reading a value #

The easiest way to read a value is by using the extension methods on [BuildContext]:

  • context.watch<T>(), which makes the widget listen to changes on T
  • context.read<T>(), which returns T without listening to it
  • context.select<T, R>(R cb(T value)), which allows a widget to listen to only a small part of T.

Or to use the static method Provider.of<T>(context), which will behave similarly to watch/read.

These methods will look up in the widget tree starting from the widget associated with the BuildContext passed, and will return the nearest variable of type T found (or throw if nothing is found).

It's worth noting that this operation is O(1). It doesn't involve actually walking in the widget tree.

Combined with the first example of exposing a value, this widget will read the exposed String and render "Hello World."

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      // Don't forget to pass the type of the object you want to obtain to `watch`!
      context.watch<String>(),
    );
  }
}

Alternatively, instead of using these methods, we can use Consumer and Selector.

These can be useful for performance optimizations or when it is difficult to obtain a BuildContext descendant of the provider.

See the FAQ or the documentation of Consumer and Selector for more information.

MultiProvider #

When injecting many values in big applications, Provider can rapidly become pretty nested:

Provider<Something>(
  create: (_) => Something(),
  child: Provider<SomethingElse>(
    create: (_) => SomethingElse(),
    child: Provider<AnotherThing>(
      create: (_) => AnotherThing(),
      child: someWidget,
    ),
  ),
),

To:

MultiProvider(
  providers: [
    Provider<Something>(create: (_) => Something()),
    Provider<SomethingElse>(create: (_) => SomethingElse()),
    Provider<AnotherThing>(create: (_) => AnotherThing()),
  ],
  child: someWidget,
)

The behavior of both examples is strictly the same. MultiProvider only changes the appearance of the code.

ProxyProvider #

Since the 3.0.0, there is a new kind of provider: ProxyProvider.

ProxyProvider is a provider that combines multiple values from other providers into a new object, and sends the result to Provider.

That new object will then be updated whenever one of the providers it depends on updates.

The following example uses ProxyProvider to build translations based on a counter coming from another provider.

Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => Counter()),
      ProxyProvider<Counter, Translations>(
        update: (_, counter, __) => Translations(counter.value),
      ),
    ],
    child: Foo(),
  );
}

class Translations {
  const Translations(this._value);

  final int _value;

  String get title => 'You clicked $_value times';
}

It comes under multiple variations, such as:

  • ProxyProvider vs ProxyProvider2 vs ProxyProvider3, ...

    That digit after the class name is the number of other providers that ProxyProvider depends on.

  • ProxyProvider vs ChangeNotifierProxyProvider vs ListenableProxyProvider, ...

    They all work similarly, but instead of sending the result into a Provider, a ChangeNotifierProxyProvider will send its value to a ChangeNotifierProvider.

FAQ #

Can I inspect the content of my objects?

Flutter comes with a devtool that shows what the widget tree is at a given moment.

Since providers are widgets, they are also visible in that devtool:

From there, if you click on one provider, you will be able to see the value it exposes:

(screenshot of the devtools using the example folder)

The devtool only shows "Instance of MyClass". What can I do?

By default, the devtool relies on toString, which defaults to "Instance of MyClass".

To have something more useful, you have two solutions:

  • use the Diagnosticable API from Flutter.

    For most cases, that will be done my using DiagnosticableTreeMixin on your objects, followed by a custom implementation of debugFillProperties.

    class MyClass with DiagnosticableTreeMixin {
      MyClass({this.a, this.b});
    
      final int a;
      final String b;
    
      @override
      void debugFillProperties(DiagnosticPropertiesBuilder properties) {
        super.debugFillProperties(properties);
        // list all the properties of your class here.
        // See the documentation of debugFillProperties for more information.
        properties.add(IntProperty('a', a));
        properties.add(StringProperty('b', b));
      }
    }
    
  • override toString.

    If you cannot use DiagnosticableTreeMixin (like if your class is in a package that does not depend on Flutter), then you can simply override toString.

    This is easier than using DiagnosticableTreeMixin but is less powerful: You will not be able to expand/collapse the details of your object.

    class MyClass with DiagnosticableTreeMixin {
      MyClass({this.a, this.b});
    
      final int a;
      final String b;
    
      @override
      String toString() {
        return '$runtimeType(a: $a, b: $b)';
      }
    }
    

I have an exception when obtaining Providers inside initState. What can I do?

This exception happens because you're trying to listen to a provider from a life-cycle that will never ever be called again.

It means that you either should use another life-cycle (didChangeDependencies/build), or explicitly specify that you do not care about updates.

As such, instead of:

initState() {
  super.initState();
  print(context.watch<Foo>().value);
}

you can do:

Value value;

didChangeDependencies() {
  super.didChangeDependencies();
  final value = context.watch<Foo>.value;
  if (value != this.value) {
    this.value = value;
    print(value);
  }
}

which will print value whenever it changes.

Alternatively you can do:

initState() {
  super.initState();
  print(context.read<Foo>().value);
}

Which will print value once and ignore updates.

I use ChangeNotifier and I have an exception when I update it, what happens?

This likely happens because you are modifying the ChangeNotifier from one of its descendants while the widget tree is building.

A typical situation where this happens is when starting an http request, where the future is stored inside the notifier:

initState() {
  super.initState();
  context.read<MyNotifier>().fetchSomething();
}

This is not allowed, because the modification is immediate.

Which means that some widgets may build before the mutation, while other widgets will build after the mutation. This could cause inconsistencies in your UI and is therefore not allowed.

Instead, you should perform that mutation in a place that would affect the entire tree equally:

  • directly inside the create of your provider/constructor of your model:

    class MyNotifier with ChangeNotifier {
      MyNotifier() {
        _fetchSomething();
      }
    
      Future<void> _fetchSomething() async {}
    }
    

    This is useful when there's no "external parameter".

  • asynchronously at the end of the frame:

    initState() {
      super.initState();
      Future.microtask(() =>
        context.read<MyNotifier>(context).fetchSomething(someValue);
      );
    }
    

    It is slightly less ideal, but allows passing parameters to the mutation.

Do I have to use ChangeNotifier for complex states?

No.

You can use any object to represent your state. For example, an alternate architecture is to use Provider.value() combined with a StatefulWidget.

Here's a counter example using such architecture:

class Example extends StatefulWidget {
  const Example({Key key, this.child}) : super(key: key);

  final Widget child;

  @override
  ExampleState createState() => ExampleState();
}

class ExampleState extends State<Example> {
  int _count;

  void increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Provider.value(
      value: _count,
      child: Provider.value(
        value: this,
        child: widget.child,
      ),
    );
  }
}

where we can read the state by doing:

return Text(context.watch<int>().toString());

and modify the state with:

return FloatingActionButton(
  onPressed: () => context.read<ExampleState>().increment(),
  child: Icon(Icons.plus_one),
);

Alternatively, you can create your own provider.

Can I make my own Provider?

Yes. provider exposes all the small components that make a fully-fledged provider.

This includes:

  • SingleChildCloneableWidget, to make any widget works with MultiProvider.
  • InheritedProvider, the generic InheritedWidget obtained when doing Provider.of.
  • DelegateWidget/BuilderDelegate/ValueDelegate to help handle the logic of "MyProvider() that creates an object" vs "MyProvider.value() that can update over time".

Here's an example of a custom provider to use ValueNotifier as state: https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91

My widget rebuilds too often, what can I do?

Instead of context.watch, you can use context.select to listen only to a specific set of properties on the obtained object.

For example, while you can write:

Widget build(BuildContext context) {
  final person = context.watch<Person>();
  return Text(person.name);
}

It may cause the widget to rebuild if something other than name changes.

Instead, you can use context.select to listen only to the name property:

Widget build(BuildContext context) {
  final name = context.select((Person p) => p.name);
  return Text(person.name);
}

This way, the widget won't unnecessarily rebuild if something other than name changes.

Similarly, you can use Consumer/Selector. Their optional child argument allows to rebuild only a very specific part of the widget tree:

Foo(
  child: Consumer<A>(
    builder: (_, a, child) {
      return Bar(a: a, child: child);
    },
    child: Baz(),
  ),
)

In this example, only Bar will rebuild when A updates. Foo and Baz won't unnecessarily rebuild.

Can I obtain two different providers using the same type?

No. While you can have multiple providers sharing the same type, a widget will be able to obtain only one of them: the closest ancestor.

Instead, you must explicitly give both providers a different type.

Instead of:

Provider<String>(
  create: (_) => 'England',
  child: Provider<String>(
    create: (_) => 'London',
    child: ...,
  ),
),

Prefer:

Provider<Country>(
  create: (_) => Country('England'),
  child: Provider<City>(
    create: (_) => City('London'),
    child: ...,
  ),
),

Can I consume an interface and provide an implementation?

Yes, a type hint must be given to the compiler to indicate the interface will be consumed, with the implementation provided in create.

abstract class ProviderInterface with ChangeNotifier {
  ...
}

class ProviderImplementation with ChangeNotifier implements ProviderInterface {
  ...
}

class Foo extends StatelessWidget {
  @override
  build(context) {
    final provider = Provider.of<ProviderInterface>(context);
    return ...
  }
}

ChangeNotifierProvider<ProviderInterface>(
  create: (_) => ProviderImplementation(),
  child: Foo(),
),

Existing providers #

provider exposes a few different kinds of "provider" for different types of objects.

The complete list of all the objects available is here

namedescription
ProviderThe most basic form of provider. It takes a value and exposes it, whatever the value is.
ListenableProviderA specific provider for Listenable object. ListenableProvider will listen to the object and ask widgets which depend on it to rebuild whenever the listener is called.
ChangeNotifierProviderA specification of ListenableProvider for ChangeNotifier. It will automatically call ChangeNotifier.dispose when needed.
ValueListenableProviderListen to a ValueListenable and only expose ValueListenable.value.
StreamProviderListen to a Stream and expose the latest value emitted.
FutureProviderTakes a Future and updates dependents when the future completes.

4.1.3 #

  • Improved the error message of ProviderNotFoundException with instructions that better fit what is usually the problem.

  • Added documentation on why context.read should not be called inside build, and what to do instead.

  • Improved the performances of context.select, by not calling the selectors when the provider changes if the widgets listening to the value are already needing build.

  • Fixes a bug where context.watch couldn't be called inside ListView/LayoutBuilder

  • Improve the error message when trying to use context.select inside ListView.builder

  • Improve the error message when calling context.read/watch/select/Provider.of with a context that is null.

4.1.2 #

  • Loosened the constraint on Flutter's version to be compatible with beta channel.

4.1.1 #

  • Fixes an "aspect" leak with context.select, leading to memory leaks and unnecessary rebuilds
  • Fixes the builder parameter of providers not working (thanks to @passsy)

4.1.0 #

  • Added a select extension on BuildContext. It behaves similarly to Selector, but is a lot less verbose to write:

    With Selector:

    Widget build(BuildContext context) {
      return Selector<Person, String>(
        selector: (_, p) => p.name,
        builder: (_, name, __) {
          return Text(name);
        },
      ),
    }
    

    VS with the new select extension:

    Widget build(BuildContext context) {
      final name = context.select((Person p) => p.name);
      return Text(name);
    }
    
  • Added builder on the different providers. This parameter simplifies situations where we need a BuildContext that can access the new provider.

    As such, instead of:

    Provider(
      create: (_) => Something(),
      child: Builder(
        builder: (context) {
          final name = context.select((Something s) => s.name);
          return Text(name);
        },
      ),
    )
    

    we can write:

    Provider(
      create: (_) => Something(),
      builder: (context, child) {
        final name = context.select((Something s) => s.name);
        return Text(name);
      },
    )
    

    The behavior is the same. This is only a small syntax sugar.

  • Added a two extensions on BuildContext, to slightly reduce the boilerplate:

    beforeafter
    Provider.of<T>(context, listen: false)context.read<T>()
    Provider.of<T>(context)context.watch<T>
  • Added a Locator typedef and an extension on BuildContext, to help with being able to read providers from a class that doesn't depend on Flutter.

4.0.5+1 #

  • Added Português translation of the readme file (thanks to @robsonsilv4)

4.0.5 #

  • Improve error message when forgetting to pass a child when using a provider outside of MultiProvider (thanks to @felangel)

4.0.4 #

  • Update the ProviderNotFoundException to remove outdated solution. (thanks @augustinreille)

4.0.3 #

  • improved error message when Provider.of is called without specifying listen: false outside of the widget tree.

4.0.2 #

  • fix Provider.of returning the previous value instead of the new value if called inside didChangeDependencies.
  • fixed an issue where update was unnecessarily called.

4.0.1 #

  • stable release of 4.0.0-hotfix+1
  • fix some typos

4.0.0-hotfix.1 #

4.0.0 #

  • Selector now deeply compares collections by default, and offers a shouldRebuild to customize the rebuild behavior.
  • renamed ProviderNotFoundError to ProviderNotFoundException. This allows calling Provider.of inside a try/catch without triggering a warning.
  • update provider to work with Flutter 1.12.1
  • The creation and listening of objects using providers is now performed lazily. This means that objects are created the first time the value is read instead of the first time the provider is mounted.
  • The listen argument of Provider.of is now automatically inferred. It is no longer necessary to pass listen: false when calling Provider.of outside of the widget tree. removed by 4.0.0-hotfix. See https://github.com/rrousselGit/provider/issues/305
  • renamed initialBuilder & builder of *ProxyProvider to create & update
  • renamed builder of *Provider to create
  • added a *ProxyProvider0 variant

3.2.0 #

  • Deprecated "builder" of providers in favor to "create"
  • Deprecated "initialBuilder"/"builder" of proxy providers in favor of respectively "create" and "update"

3.1.0 #

  • Added Selector, similar to Consumer but can filter unneeded updates
  • improved the overall documentation
  • fixed a bug where ChangeNotifierProvider.value didn't update dependents when the ChangeNotifier instance changed.
  • Consumer can now be used inside MultiProvider
    MultiProvider(
      providers: [
        Provider(builder: (_) => Foo()),
        Consumer<Foo>(
          builder: (context, foo, child) =>
            Provider.value(value: foo.bar, child: child),
        )
      ],
    );
    

3.0.0 #

breaking (see the readme for migration steps): #

  • Provider now throws if used with a Listenable/Stream. This can be disabled by setting Provider.debugCheckInvalidValueType to null.
  • The default constructor of StreamProvider has now builds a Stream instead of StreamController. The previous behavior has been moved to StreamProvider.controller.
  • All XXProvider.value constructors now use value as parameter name.
  • Added FutureProvider, which takes a future and updates dependents when the future completes.
  • Providers can no longer be instantiated using const constructors.

non-breaking: #

  • Added ProxyProvider, ListenableProxyProvider, and ChangeNotifierProxyProvider. These providers allows building values that depends on other providers, without loosing reactivity or manually handling the state.
  • Added DelegateWidget and a few related classes to help building custom providers.
  • Exposed the internal generic InheritedWidget to help building custom providers.

2.0.1 #

  • fix a bug where ListenableProvider.value/ChangeNotifierProvider.value /StreamProvider.value/ValueListenableProvider.value subscribed/unsubscribed to their respective object too often
  • fix a bug where ListenableProvider.value/ChangeNotifierProvider.value may rebuild too often or skip some.

2.0.0 #

  • Consumer now takes an optional child argument for optimization purposes.
  • merged Provider and StatefulProvider
  • added a "builder" constructor to ValueListenableProvider
  • normalized providers constructors such that the default constructor is a "builder", and offer a value named constructor.

1.6.1 #

  • Provider.of<T> now crashes with a ProviderNotFoundException when no Provider<T> are found in the ancestors of the context used.

1.6.0 #

  • new: ChangeNotifierProvider, similar to scoped_model that exposes ChangeNotifer subclass and rebuilds dependents only when notifyListeners is called.
  • new: ValueListenableProvider, a provider that rebuilds whenever the value passed to a ValueNotifier change.

1.5.0 #

  • new: Add Consumer with up to 6 parameters.
  • new: MultiProvider, a provider that makes a tree of provider more readable
  • new: StreamProvider, a stream that exposes to its descendants the current value of a Stream.

1.4.0 #

  • Reintroduced StatefulProvider with a modified prototype. The second argument of valueBuilder and didChangeDependencies have been removed. And valueBuilder is now called only once for the whole life-cycle of StatefulProvider.

1.3.0 #

  • Added Consumer, useful when we need to both expose and consume a value simultaneously.

1.2.0 #

  • Added: HookProvider, a Provider that creates its value from a Hook.
  • Deprecated StatefulProvider. Either make a StatefulWidget or use HookProvider.
  • Integrated the widget inspector, so that Provider widget shows the current value.

1.1.1 #

  • add didChangeDependencies callback to allow updating the value based on an InheritedWidget
  • add updateShouldNotify method to both Provider and StatefulProvider

1.1.0 #

  • onDispose has been added to StatefulProvider
  • BuildContext is now passed to valueBuilder callback

example/lib/main.dart

// ignore_for_file: public_member_api_docs, lines_longer_than_80_chars
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

/// This is a reimplementation of the default Flutter application using provider + [ChangeNotifier].

void main() {
  runApp(
    /// Providers are above [MyApp] instead of inside it, so that tests
    /// can use [MyApp] while mocking the providers
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Counter()),
      ],
      child: MyApp(),
    ),
  );
}

/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool
class Counter with ChangeNotifier, DiagnosticableTreeMixin {
  int _count = 0;
  int get count => _count;

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

  /// Makes `Counter` readable inside the devtools by listing all of its properties
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('count', count));
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),

            /// Extracted as a separate widget for performance optimization.
            /// As a separate widget, it will rebuild independently from [MyHomePage].
            ///
            /// This is totally optional (and rarely needed).
            /// Similarly, we could also use [Consumer] or [Selector].
            const Count(),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        /// Calls `context.read` instead of `context.watch` so that it does not rebuild
        /// when [Counter] changes.
        onPressed: () => context.read<Counter>().increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class Count extends StatelessWidget {
  const Count({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(

        /// Calls `context.watch` to make [MyHomePage] rebuild when [Counter] changes.
        '${context.watch<Counter>().count}',
        style: Theme.of(context).textTheme.headline4);
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  provider: ^4.1.3

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:provider/provider.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
100
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
100
Learn more about scoring.

We analyzed this package on Jun 5, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.2
  • pana: 0.13.8-dev
  • Flutter: 1.17.1

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0
collection ^1.14.0 1.14.12
flutter 0.0.0
nested >=0.0.4 <2.0.0 0.0.4
Transitive dependencies
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test
mockito ^4.0.0