CINXE.COM

provider | Flutter package

<!DOCTYPE html> <html lang="en-us"><head><script src="https://www.googletagmanager.com/gtm.js?id=GTM-MX6DBN9" async="async"></script><script src="/static/hash-o6oemknr/js/gtm.js" async="async"></script><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="ie=edge"/><meta name="viewport" content="width=device-width, initial-scale=1"/><meta name="twitter:card" content="summary"/><meta name="twitter:site" content="@dart_lang"/><meta name="twitter:description" content="A wrapper around InheritedWidget to make them easier to use and more reusable."/><meta name="twitter:image" content="https://pub.dev/static/hash-o6oemknr/img/pub-dev-icon-cover-image.png"/><meta property="og:type" content="website"/><meta property="og:site_name" content="Dart packages"/><meta property="og:title" content="provider | Flutter package"/><meta property="og:description" content="A wrapper around InheritedWidget to make them easier to use and more reusable."/><meta property="og:image" content="https://pub.dev/static/hash-o6oemknr/img/pub-dev-icon-cover-image.png"/><meta property="og:url" content="https://pub.dev/packages/provider"/><title>provider | Flutter package</title><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&amp;family=Google+Sans+Display:wght@400&amp;family=Google+Sans+Text:wght@400;500;700&amp;family=Google+Sans+Mono:wght@400;700&amp;display=swap"/><link rel="shortcut icon" href="/static/hash-o6oemknr/img/flutter-logo-32x32.png"/><link rel="stylesheet" href="https://www.gstatic.com/glue/v25_0/ccb.min.css"/><link rel="search" type="application/opensearchdescription+xml" title="Dart packages" href="/osd.xml"/><link rel="canonical" href="https://pub.dev/packages/provider"/><meta name="description" content="A wrapper around InheritedWidget to make them easier to use and more reusable."/><link rel="alternate" type="application/atom+xml" title="Updated Packages Feed for Pub" href="/feed.atom"/><link rel="stylesheet" type="text/css" href="/static/hash-o6oemknr/material/bundle/styles.css"/><link rel="stylesheet" type="text/css" href="/static/hash-o6oemknr/css/style.css"/><script src="/static/hash-o6oemknr/material/bundle/script.min.js" defer="defer"></script><script src="/static/hash-o6oemknr/js/script.dart.js" defer="defer"></script><script src="https://www.gstatic.com/brandstudio/kato/cookie_choice_component/cookie_consent_bar.v3.js" defer="defer" data-autoload-cookie-consent-bar="true"></script><meta name="pub-page-data" content="eyJwa2dEYXRhIjp7InBhY2thZ2UiOiJwcm92aWRlciIsInZlcnNpb24iOiI2LjEuMiIsImxpa2VzIjoxMDM4MiwicHVibGlzaGVySWQiOiJkYXNoLW92ZXJmbG93Lm5ldCIsImlzRGlzY29udGludWVkIjpmYWxzZSwiaXNMYXRlc3QiOnRydWV9LCJzZXNzaW9uQXdhcmUiOmZhbHNlfQ=="/><link rel="preload" href="/static/hash-o6oemknr/highlight/highlight-with-init.js" as="script"/></head><body class="light-theme"><script src="/static/hash-o6oemknr/js/dark-init.js"></script><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-MX6DBN9" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div class="site-header"><button class="hamburger" aria-label="menu toggle"></button><a class="logo" href="/"><img class="site-logo" src="/static/hash-o6oemknr/img/pub-dev-logo.svg" alt="" width="140" height="30" role="presentation"/></a><div class="site-header-space"></div><div class="site-header-mask"></div><div class="site-header-search"><form action="/packages" method="GET"><input class="site-header-search-input" name="q" placeholder="New search..." autocomplete="on" title="Search"/></form></div><nav class="site-header-nav scroll-container"><div class="nav-login-container"><button id="-account-login" class="nav-main-button link">Sign in</button></div><div class="nav-container nav-help-container hoverable"><button class="nav-main-button">Help</button><div class="nav-hover-popup"><div class="nav-table-columns"><div class="nav-table-column"><h3>Pub.dev</h3><a class="nav-link" href="/help/search" rel="noopener" target="_blank">Searching for packages</a><a class="nav-link" href="/help/scoring" rel="noopener" target="_blank">Package scoring and pub points</a></div><div class="nav-table-column"><h3>Flutter</h3><a class="nav-link" href="https://flutter.dev/using-packages/" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://flutter.dev/developing-packages/" rel="noopener" target="_blank">Developing packages and plugins</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div><div class="nav-table-column"><h3>Dart</h3><a class="nav-link" href="https://dart.dev/guides/packages" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div></div></div></div><div class="nav-container nav-help-container-mobile foldable"><h3 class="foldable-button">Pub.dev <img class="foldable-icon" src="/static/hash-o6oemknr/img/nav-mobile-foldable-icon.svg" alt="toggle folding of the section" width="13" height="6"/></h3><div class="foldable-content"><a class="nav-link" href="/help/search" rel="noopener" target="_blank">Searching for packages</a><a class="nav-link" href="/help/scoring" rel="noopener" target="_blank">Package scoring and pub points</a></div></div><div class="nav-container nav-help-container-mobile foldable"><h3 class="foldable-button">Flutter <img class="foldable-icon" src="/static/hash-o6oemknr/img/nav-mobile-foldable-icon.svg" alt="toggle folding of the section" width="13" height="6"/></h3><div class="foldable-content"><a class="nav-link" href="https://flutter.dev/using-packages/" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://flutter.dev/developing-packages/" rel="noopener" target="_blank">Developing packages and plugins</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div></div><div class="nav-container nav-help-container-mobile foldable"><h3 class="foldable-button">Dart <img class="foldable-icon" src="/static/hash-o6oemknr/img/nav-mobile-foldable-icon.svg" alt="toggle folding of the section" width="13" height="6"/></h3><div class="foldable-content"><a class="nav-link" href="https://dart.dev/guides/packages" rel="noopener" target="_blank">Using packages</a><a class="nav-link" href="https://dart.dev/tools/pub/publishing" rel="noopener" target="_blank">Publishing a package</a></div></div></nav></div><div id="banner-container"></div><main class="container"><div class="detail-wrapper -active -has-info-box"><div class="detail-banners"><a href="https://flutter.dev/docs/development/packages-and-plugins/favorites" rel="noopener" target="_blank"><img class="ff-banner ff-banner-desktop displayed-in-light-theme" src="/static/hash-o6oemknr/img/ff-banner-desktop-2x.png" alt="" width="150" height="218" title="Package is a Flutter Favorite" role="presentation"/><img class="ff-banner ff-banner-desktop displayed-in-dark-theme" src="/static/hash-o6oemknr/img/ff-banner-desktop-dark-2x.png" alt="" width="150" height="218" title="Package is a Flutter Favorite" role="presentation"/><img class="ff-banner ff-banner-mobile displayed-in-light-theme" src="/static/hash-o6oemknr/img/ff-banner-mobile-2x.png" alt="" width="94" height="116" title="Package is a Flutter Favorite" role="presentation"/><img class="ff-banner ff-banner-mobile displayed-in-dark-theme" src="/static/hash-o6oemknr/img/ff-banner-mobile-dark-2x.png" alt="" width="94" height="116" title="Package is a Flutter Favorite" role="presentation"/></a></div><div class="detail-header -is-loose"><div class="detail-container"><div class="detail-header-outer-block"><div class="detail-header-content-block"><h1 class="title">provider 6.1.2 <span class="pkg-page-title-copy"><img class="pkg-page-title-copy-icon filter-invert-on-dark" src="/static/hash-o6oemknr/img/content-copy-icon.svg" alt="copy &quot;provider: ^6.1.2&quot; to clipboard" width="18" height="18" title="Copy &quot;provider: ^6.1.2&quot; to clipboard" data-copy-content="provider: ^6.1.2" data-ga-click-event="copy-package-version"/><div class="pkg-page-title-copy-feedback"><span class="code">provider: ^6.1.2</span> copied to clipboard</div></span></h1><div class="metadata">Published <span><a class="-x-ago" href="" title="Feb 28, 2024" aria-label="9 months ago" aria-role="button" role="button" data-timestamp="1709140174887">9 months ago</a></span> • <a class="-pub-publisher" href="/publishers/dash-overflow.net"><img class="-pub-publisher-shield filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-verified.svg" alt="verified publisher" width="14" height="14" title="Published by a pub.dev verified publisher"/>dash-overflow.net</a><span class="package-badge" title="Package is compatible with Dart 3.">Dart 3 compatible</span></div><div class="detail-tags-and-like"><div class="detail-tags"><div class="-pub-tag-badge"><span class="tag-badge-main">SDK</span><a class="tag-badge-sub" href="/packages?q=sdk%3Aflutter" rel="nofollow" title="Packages compatible with Flutter SDK">Flutter</a></div><div class="-pub-tag-badge"><span class="tag-badge-main">Platform</span><a class="tag-badge-sub" href="/packages?q=platform%3Aandroid" rel="nofollow" title="Packages compatible with Android platform">Android</a><a class="tag-badge-sub" href="/packages?q=platform%3Aios" rel="nofollow" title="Packages compatible with iOS platform">iOS</a><a class="tag-badge-sub" href="/packages?q=platform%3Alinux" rel="nofollow" title="Packages compatible with Linux platform">Linux</a><a class="tag-badge-sub" href="/packages?q=platform%3Amacos" rel="nofollow" title="Packages compatible with macOS platform">macOS</a><a class="tag-badge-sub" href="/packages?q=platform%3Aweb" rel="nofollow" title="Packages compatible with Web platform">web</a><a class="tag-badge-sub" href="/packages?q=platform%3Awindows" rel="nofollow" title="Packages compatible with Windows platform">Windows</a></div></div><div class="detail-like"><button id="-pub-like-icon-button" class="mdc-icon-button" data-ga-click-event="toggle-like" aria-pressed="false" title="Like this package"><img class="mdc-icon-button__icon" src="/static/hash-o6oemknr/img/like-inactive.svg" alt="liked status: inactive" width="18" height="18"/><img class="mdc-icon-button__icon mdc-icon-button__icon--on" src="/static/hash-o6oemknr/img/like-active.svg" alt="liked status: active" width="18" height="18"/></button><span class="likes-count"><span id="likes-count">10.3k</span></span></div></div></div></div></div></div><div class="detail-container"><div class="detail-lead"><div class="detail-metadata-toggle"><div class="detail-metadata-toggle-icon">→</div><h3 class="detail-lead-title">Metadata</h3></div><p class="detail-lead-text">A wrapper around InheritedWidget to make them easier to use and more reusable.</p><p class="detail-lead-more"><a class="detail-metadata-toggle">More...</a></p></div></div><div class="detail-body"><div class="detail-tabs"><div class="detail-tabs-wide-header"><div class="detail-container"><ul class="detail-tabs-header"><li class="detail-tab tab-button detail-tab-readme-title -active">Readme</li><li class="detail-tab tab-link detail-tab-changelog-title"><a href="/packages/provider/changelog" role="button">Changelog</a></li><li class="detail-tab tab-link detail-tab-example-title"><a href="/packages/provider/example" role="button">Example</a></li><li class="detail-tab tab-link detail-tab-installing-title"><a href="/packages/provider/install" role="button">Installing</a></li><li class="detail-tab tab-link detail-tab-versions-title"><a href="/packages/provider/versions" role="button">Versions</a></li><li class="detail-tab tab-link detail-tab-analysis-title"><a href="/packages/provider/score" role="button">Scores</a></li></ul></div></div><div class="detail-container detail-body-main"><div class="detail-tabs-content"><section class="tab-content detail-tab-readme-content -active markdown-body"><p><a href="https://github.com/rrousselGit/provider/blob/master/packages/provider/README.md" rel="ugc">English</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/fr_FR/README.md" rel="ugc">French</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/pt_br/README.md" rel="ugc">Português</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/zh-CN/README.md" rel="ugc">简体中文</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/es_MX/README.md" rel="ugc">Español</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/ko-KR/README.md" rel="ugc">한국어</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/bn_BD/README.md" rel="ugc">বাংলা</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/ja_JP/README.md" rel="ugc">日本語</a> | <a href="https://github.com/rrousselGit/provider/blob/master/resources/translations/tr_TR/README.md" rel="ugc">Turkish</a></p> <p><a href="https://github.com/rrousselGit/provider/actions" rel="ugc"><img src="https://github.com/rrousselGit/provider/workflows/Build/badge.svg" alt="Build Status"></a> <a href="https://codecov.io/gh/rrousselGit/provider" rel="ugc"><img src="https://codecov.io/gh/rrousselGit/provider/branch/master/graph/badge.svg" alt="codecov"></a> <a href="https://discord.gg/Bbumvej" rel="ugc"><img src="https://img.shields.io/discord/765557403865186374.svg?logo=discord&amp;color=blue" alt="Discord"></a></p> <p><a href="https://flutter.dev/docs/development/packages-and-plugins/favorites"><img src="https://raw.githubusercontent.com/rrousselGit/provider/master/resources/flutter_favorite.png" width="200"></a></p> <p>A wrapper around <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> to make them easier to use and more reusable.</p> <p>By using <code>provider</code> instead of manually writing <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a>, you get:</p> <ul> <li>simplified allocation/disposal of resources</li> <li>lazy-loading</li> <li>a vastly reduced boilerplate over making a new class every time</li> <li>devtool friendly – using Provider, the state of your application will be visible in the Flutter devtool</li> <li>a common way to consume these <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a>s (See <a href="https://pub.dev/documentation/provider/latest/provider/Provider/of.html">Provider.of</a>/<a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a>/<a href="https://pub.dev/documentation/provider/latest/provider/Selector-class.html">Selector</a>)</li> <li>increased scalability for classes with a listening mechanism that grows exponentially in complexity (such as <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>, which is O(N) for dispatching notifications).</li> </ul> <p>To read more about a <code>provider</code>, see its <a href="https://pub.dev/documentation/provider/latest/provider/provider-library.html">documentation</a>.</p> <p>See also:</p> <ul> <li><a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple">The official Flutter state management documentation</a>, which showcases how to use <code>provider</code> + <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a></li> <li><a href="https://github.com/brianegan/flutter_architecture_samples/tree/master/change_notifier_provider" rel="ugc">flutter architecture sample</a>, which contains an implementation of that app using <code>provider</code> + <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a></li> <li><a href="https://github.com/felangel/bloc" rel="ugc">flutter_bloc</a> and <a href="https://github.com/mobxjs/mobx.dart" rel="ugc">Mobx</a>, which uses a <code>provider</code> in their architecture</li> </ul> <h2 class="hash-header" id="migration-from-4xx-to-500-nullsafety">Migration from 4.x.x to 5.0.0-nullsafety <a href="#migration-from-4xx-to-500-nullsafety" class="hash-link">#</a></h2> <ul> <li> <p><code>initialData</code> for both <code>FutureProvider</code> and <code>StreamProvider</code> is now required.</p> <p>To migrate, what used to be:</p> <pre><code class="language-dart">FutureProvider&lt;int&gt;( create: (context) =&gt; Future.value(42), child: MyApp(), ) Widget build(BuildContext context) { final value = context.watch&lt;int&gt;(); return Text('$value'); } </code></pre> <p>is now:</p> <pre><code class="language-dart">FutureProvider&lt;int?&gt;( initialValue: null, create: (context) =&gt; Future.value(42), child: MyApp(), ) Widget build(BuildContext context) { // be sure to specify the ? in watch&lt;int?&gt; final value = context.watch&lt;int?&gt;(); return Text('$value'); } </code></pre> </li> <li> <p><code>ValueListenableProvider</code> is removed</p> <p>To migrate, you can instead use <code>Provider</code> combined with <code>ValueListenableBuilder</code>:</p> <pre><code class="language-dart">ValueListenableBuilder&lt;int&gt;( valueListenable: myValueListenable, builder: (context, value, _) { return Provider&lt;int&gt;.value( value: value, child: MyApp(), ); } ) </code></pre> </li> </ul> <h2 class="hash-header" id="usage">Usage <a href="#usage" class="hash-link">#</a></h2> <h3 class="hash-header" id="exposing-a-value">Exposing a value <a href="#exposing-a-value" class="hash-link">#</a></h3> <h4 id="exposing-a-new-object-instance">Exposing a new object instance</h4> <p>Providers allow you to not only expose a value, but also create, listen, and dispose of it.</p> <p>To expose a newly created object, use the default constructor of a provider. Do <em>not</em> use the <code>.value</code> constructor if you want to <strong>create</strong> an object, or you may otherwise have undesired side effects.</p> <p>See <a href="https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build" rel="ugc">this StackOverflow answer</a> which explains why using the <code>.value</code> constructor to create values is undesired.</p> <ul> <li><strong>DO</strong> create a new object inside <code>create</code>.</li> </ul> <pre><code class="language-dart">Provider( create: (_) =&gt; MyModel(), child: ... ) </code></pre> <ul> <li><strong>DON'T</strong> use <code>Provider.value</code> to create your object.</li> </ul> <pre><code class="language-dart">ChangeNotifierProvider.value( value: MyModel(), child: ... ) </code></pre> <ul> <li> <p><strong>DON'T</strong> create your object from variables that can change over time.</p> <p>In such a situation, your object would never update when the value changes.</p> </li> </ul> <pre><code class="language-dart">int count; Provider( create: (_) =&gt; MyModel(count), child: ... ) </code></pre> <p>If you want to pass variables that can change over time to your object, consider using <code>ProxyProvider</code>:</p> <pre><code class="language-dart">int count; ProxyProvider0( update: (_, __) =&gt; MyModel(count), child: ... ) </code></pre> <p><strong>NOTE</strong>:</p> <p>When using the <code>create</code>/<code>update</code> callback of a provider, it is worth noting that this callback is called lazily by default.</p> <p>This means that until the value is requested at least once, the <code>create</code>/<code>update</code> callbacks won't be called.</p> <p>This behavior can be disabled if you want to pre-compute some logic, using the <code>lazy</code> parameter:</p> <pre><code class="language-dart">MyProvider( create: (_) =&gt; Something(), lazy: false, ) </code></pre> <h4 id="reusing-an-existing-object-instance">Reusing an existing object instance:</h4> <p>If you already have an object instance and want to expose it, it would be best to use the <code>.value</code> constructor of a provider.</p> <p>Failing to do so may call your object <code>dispose</code> method when it is still in use.</p> <ul> <li><strong>DO</strong> use <code>ChangeNotifierProvider.value</code> to provide an existing <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>.</li> </ul> <pre><code class="language-dart">MyChangeNotifier variable; ChangeNotifierProvider.value( value: variable, child: ... ) </code></pre> <ul> <li><strong>DON'T</strong> reuse an existing <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> using the default constructor</li> </ul> <pre><code class="language-dart">MyChangeNotifier variable; ChangeNotifierProvider( create: (_) =&gt; variable, child: ... ) </code></pre> <h3 class="hash-header" id="reading-a-value">Reading a value <a href="#reading-a-value" class="hash-link">#</a></h3> <p>The easiest way to read a value is by using the extension methods on [BuildContext]:</p> <ul> <li><code>context.watch&lt;T&gt;()</code>, which makes the widget listen to changes on <code>T</code></li> <li><code>context.read&lt;T&gt;()</code>, which returns <code>T</code> without listening to it</li> <li><code>context.select&lt;T, R&gt;(R cb(T value))</code>, which allows a widget to listen to only a small part of <code>T</code>.</li> </ul> <p>One can also use the static method <code>Provider.of&lt;T&gt;(context)</code>, which will behave similarly to <code>watch</code>. When the <code>listen</code> parameter is set to <code>false</code> (as in <code>Provider.of&lt;T&gt;(context, listen: false)</code>), then it will behave similarly to <code>read</code>.</p> <p>It's worth noting that <code>context.read&lt;T&gt;()</code> won't make a widget rebuild when the value changes and it cannot be called inside <code>StatelessWidget.build</code>/<code>State.build</code>. On the other hand, it can be freely called outside of these methods.</p> <p>These methods will look up in the widget tree starting from the widget associated with the <code>BuildContext</code> passed and will return the nearest variable of type <code>T</code> found (or throw if nothing is found).</p> <p>This operation is O(1). It doesn't involve walking in the widget tree.</p> <p>Combined with the first example of <a href="#exposing-a-value">exposing a value</a>, this widget will read the exposed <code>String</code> and render "Hello World."</p> <pre><code class="language-dart">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&lt;String&gt;(), ); } } </code></pre> <p>Alternatively, instead of using these methods, we can use <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> and <a href="https://pub.dev/documentation/provider/latest/provider/Selector-class.html">Selector</a>.</p> <p>These can be useful for performance optimizations or when it is difficult to obtain a <code>BuildContext</code> descendant of the provider.</p> <p>See the <a href="https://github.com/rrousselGit/provider#my-widget-rebuilds-too-often-what-can-i-do" rel="ugc">FAQ</a> or the documentation of <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> and <a href="https://pub.dev/documentation/provider/latest/provider/Selector-class.html">Selector</a> for more information.</p> <h3 class="hash-header" id="optionally-depending-on-a-provider">Optionally depending on a provider <a href="#optionally-depending-on-a-provider" class="hash-link">#</a></h3> <p>Sometimes, we may want to support cases where a provider does not exist. An example would be for reusable widgets that could be used in various locations, including outside of a provider.</p> <p>To do so, when calling <code>context.watch</code>/<code>context.read</code>, make the generic type nullable. Such that instead of:</p> <pre><code class="language-dart">context.watch&lt;Model&gt;() </code></pre> <p>which will throw a <code>ProviderNotFoundException</code> if no matching providers are found, do:</p> <pre><code class="language-dart">context.watch&lt;Model?&gt;() </code></pre> <p>which will try to obtain a matching provider. But if none are found, <code>null</code> will be returned instead of throwing.</p> <h3 class="hash-header" id="multiprovider">MultiProvider <a href="#multiprovider" class="hash-link">#</a></h3> <p>When injecting many values in big applications, <code>Provider</code> can rapidly become pretty nested:</p> <pre><code class="language-dart">Provider&lt;Something&gt;( create: (_) =&gt; Something(), child: Provider&lt;SomethingElse&gt;( create: (_) =&gt; SomethingElse(), child: Provider&lt;AnotherThing&gt;( create: (_) =&gt; AnotherThing(), child: someWidget, ), ), ), </code></pre> <p>To:</p> <pre><code class="language-dart">MultiProvider( providers: [ Provider&lt;Something&gt;(create: (_) =&gt; Something()), Provider&lt;SomethingElse&gt;(create: (_) =&gt; SomethingElse()), Provider&lt;AnotherThing&gt;(create: (_) =&gt; AnotherThing()), ], child: someWidget, ) </code></pre> <p>The behavior of both examples is strictly the same. <code>MultiProvider</code> only changes the appearance of the code.</p> <h3 class="hash-header" id="proxyprovider">ProxyProvider <a href="#proxyprovider" class="hash-link">#</a></h3> <p>Since the 3.0.0, there is a new kind of provider: <code>ProxyProvider</code>.</p> <p><code>ProxyProvider</code> is a provider that combines multiple values from other providers into a new object and sends the result to <code>Provider</code>.</p> <p>That new object will then be updated whenever one of the provider we depend on gets updated.</p> <p>The following example uses <code>ProxyProvider</code> to build translations based on a counter coming from another provider.</p> <pre><code class="language-dart">Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider(create: (_) =&gt; Counter()), ProxyProvider&lt;Counter, Translations&gt;( update: (_, counter, __) =&gt; Translations(counter.value), ), ], child: Foo(), ); } class Translations { const Translations(this._value); final int _value; String get title =&gt; 'You clicked $_value times'; } </code></pre> <p>It comes under multiple variations, such as:</p> <ul> <li> <p><code>ProxyProvider</code> vs <code>ProxyProvider2</code> vs <code>ProxyProvider3</code>, ...</p> <p>That digit after the class name is the number of other providers that <code>ProxyProvider</code> depends on.</p> </li> <li> <p><code>ProxyProvider</code> vs <code>ChangeNotifierProxyProvider</code> vs <code>ListenableProxyProvider</code>, ...</p> <p>They all work similarly, but instead of sending the result into a <code>Provider</code>, a <code>ChangeNotifierProxyProvider</code> will send its value to a <code>ChangeNotifierProvider</code>.</p> </li> </ul> <h3 class="hash-header" id="faq">FAQ <a href="#faq" class="hash-link">#</a></h3> <h4 id="can-i-inspect-the-content-of-my-objects">Can I inspect the content of my objects?</h4> <p>Flutter comes with a <a href="https://github.com/flutter/devtools" rel="ugc">devtool</a> that shows what the widget tree is at a given moment.</p> <p>Since providers are widgets, they are also visible in that devtool:</p> <img src="https://raw.githubusercontent.com/rrousselGit/provider/master/resources/devtools_providers.jpg" width="200"> <p>From there, if you click on one provider, you will be able to see the value it exposes:</p> <img src="https://raw.githubusercontent.com/rrousselGit/provider/master/resources/expanded_devtools.jpg" width="200"> <p>(screenshot of the devtools using the <code>example</code> folder)</p> <h4 id="the-devtool-only-shows-instance-of-myclass-what-can-i-do">The devtool only shows "Instance of MyClass". What can I do?</h4> <p>By default, the devtool relies on <code>toString</code>, which defaults to "Instance of MyClass".</p> <p>To have something more useful, you have two solutions:</p> <ul> <li> <p>use the <a href="https://api.flutter.dev/flutter/foundation/Diagnosticable-mixin.html">Diagnosticable</a> API from Flutter.</p> <p>For most cases, I will use <a href="https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin-mixin.html">DiagnosticableTreeMixin</a> on your objects, followed by a custom implementation of <a href="https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin/debugFillProperties.html">debugFillProperties</a>.</p> <pre><code class="language-dart">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)); } } </code></pre> </li> <li> <p>Override <code>toString</code>.</p> <p>If you cannot use <a href="https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin-mixin.html">DiagnosticableTreeMixin</a> (like if your class is in a package that does not depend on Flutter), then you can override <code>toString</code>.</p> <p>This is easier than using <a href="https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin-mixin.html">DiagnosticableTreeMixin</a> but is less powerful: You will not be able to expand/collapse the details of your object.</p> <pre><code class="language-dart">class MyClass with DiagnosticableTreeMixin { MyClass({this.a, this.b}); final int a; final String b; @override String toString() { return '$runtimeType(a: $a, b: $b)'; } } </code></pre> </li> </ul> <h4 id="i-have-an-exception-when-obtaining-providers-inside-initstate-what-can-i-do">I have an exception when obtaining Providers inside <code>initState</code>. What can I do?</h4> <p>This exception happens because you're trying to listen to a provider from a life-cycle that will never ever be called again.</p> <p>It means that you either should use another life-cycle (<code>build</code>), or explicitly specify that you do not care about updates.</p> <p>As such, instead of:</p> <pre><code class="language-dart">initState() { super.initState(); print(context.watch&lt;Foo&gt;().value); } </code></pre> <p>you can do:</p> <pre><code class="language-dart">Value value; Widget build(BuildContext context) { final value = context.watch&lt;Foo&gt;().value; if (value != this.value) { this.value = value; print(value); } } </code></pre> <p>which will print <code>value</code> whenever it changes (and only when it changes).</p> <p>Alternatively, you can do:</p> <pre><code class="language-dart">initState() { super.initState(); print(context.read&lt;Foo&gt;().value); } </code></pre> <p>Which will print <code>value</code> once <em>and ignore updates.</em></p> <h4 id="how-to-handle-hot-reload-on-my-objects">How to handle hot-reload on my objects?</h4> <p>You can make your provided object implement <code>ReassembleHandler</code>:</p> <pre><code class="language-dart">class Example extends ChangeNotifier implements ReassembleHandler { @override void reassemble() { print('Did hot-reload'); } } </code></pre> <p>Then used typically with <code>provider</code>:</p> <pre><code class="language-dart">ChangeNotifierProvider(create: (_) =&gt; Example()), </code></pre> <h4 id="i-use-changenotifier-and-i-have-an-exception-when-i-update-it-what-happens">I use <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>, and I have an exception when I update it. What happens?</h4> <p>This likely happens because you are modifying the <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> from one of its descendants <em>while the widget tree is building</em>.</p> <p>A typical situation where this happens is when starting an http request, where the future is stored inside the notifier:</p> <pre><code class="language-dart">initState() { super.initState(); context.read&lt;MyNotifier&gt;().fetchSomething(); } </code></pre> <p>This is not allowed because the state update is synchronous.</p> <p>This means that some widgets may build <em>before</em> the mutation happens (getting an old value), while other widgets will build <em>after</em> the mutation is complete (getting a new value). This could cause inconsistencies in your UI and is therefore not allowed.</p> <p>Instead, you should perform that mutation in a place that would affect the entire tree equally:</p> <ul> <li> <p>directly inside the <code>create</code> of your provider/constructor of your model:</p> <pre><code class="language-dart">class MyNotifier with ChangeNotifier { MyNotifier() { _fetchSomething(); } Future&lt;void&gt; _fetchSomething() async {} } </code></pre> <p>This is useful when there's no "external parameter".</p> </li> <li> <p>asynchronously at the end of the frame:</p> <pre><code class="language-dart">initState() { super.initState(); Future.microtask(() =&gt; context.read&lt;MyNotifier&gt;().fetchSomething(someValue); ); } </code></pre> <p>It is slightly less ideal, but allows passing parameters to the mutation.</p> </li> </ul> <h4 id="do-i-have-to-use-changenotifier-for-complex-states">Do I have to use <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> for complex states?</h4> <p>No.</p> <p>You can use any object to represent your state. For example, an alternate architecture is to use <code>Provider.value()</code> combined with a <code>StatefulWidget</code>.</p> <p>Here's a counter example using such architecture:</p> <pre><code class="language-dart">class Example extends StatefulWidget { const Example({Key key, this.child}) : super(key: key); final Widget child; @override ExampleState createState() =&gt; ExampleState(); } class ExampleState extends State&lt;Example&gt; { int _count; void increment() { setState(() { _count++; }); } @override Widget build(BuildContext context) { return Provider.value( value: _count, child: Provider.value( value: this, child: widget.child, ), ); } } </code></pre> <p>where we can read the state by doing:</p> <pre><code class="language-dart">return Text(context.watch&lt;int&gt;().toString()); </code></pre> <p>and modify the state with:</p> <pre><code class="language-dart">return FloatingActionButton( onPressed: () =&gt; context.read&lt;ExampleState&gt;().increment(), child: Icon(Icons.plus_one), ); </code></pre> <p>Alternatively, you can create your own provider.</p> <h4 id="can-i-make-my-provider">Can I make my Provider?</h4> <p>Yes. <code>provider</code> exposes all the small components that make a fully-fledged provider.</p> <p>This includes:</p> <ul> <li> <p><code>SingleChildStatelessWidget</code>, to make any widget works with <code>MultiProvider</code>. This interface is exposed as part of <code>package:provider/single_child_widget</code></p> </li> <li> <p><a href="https://pub.dev/documentation/provider/latest/provider/InheritedProvider-class.html">InheritedProvider</a>, the generic <code>InheritedWidget</code> obtained when doing <code>context.watch</code>.</p> </li> </ul> <p>Here's an example of a custom provider to use <code>ValueNotifier</code> as the state: <a href="https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91" rel="ugc">https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91</a></p> <h4 id="my-widget-rebuilds-too-often-what-can-i-do">My widget rebuilds too often. What can I do?</h4> <p>Instead of <code>context.watch</code>, you can use <code>context.select</code> to listen only to the specific set of properties on the obtained object.</p> <p>For example, while you can write:</p> <pre><code class="language-dart">Widget build(BuildContext context) { final person = context.watch&lt;Person&gt;(); return Text(person.name); } </code></pre> <p>It may cause the widget to rebuild if something other than <code>name</code> changes.</p> <p>Instead, you can use <code>context.select</code> to listen only to the <code>name</code> property:</p> <pre><code class="language-dart">Widget build(BuildContext context) { final name = context.select((Person p) =&gt; p.name); return Text(name); } </code></pre> <p>This way, the widget won't unnecessarily rebuild if something other than <code>name</code> changes.</p> <p>Similarly, you can use <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a>/<a href="https://pub.dev/documentation/provider/latest/provider/Selector-class.html">Selector</a>. Their optional <code>child</code> argument allows rebuilding only a particular part of the widget tree:</p> <pre><code class="language-dart">Foo( child: Consumer&lt;A&gt;( builder: (_, a, child) { return Bar(a: a, child: child); }, child: Baz(), ), ) </code></pre> <p>In this example, only <code>Bar</code> will rebuild when <code>A</code> updates. <code>Foo</code> and <code>Baz</code> won't unnecessarily rebuild.</p> <h4 id="can-i-obtain-two-different-providers-using-the-same-type">Can I obtain two different providers using the same type?</h4> <p>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.</p> <p>Instead, it would help if you explicitly gave both providers a different type.</p> <p>Instead of:</p> <pre><code class="language-dart">Provider&lt;String&gt;( create: (_) =&gt; 'England', child: Provider&lt;String&gt;( create: (_) =&gt; 'London', child: ..., ), ), </code></pre> <p>Prefer:</p> <pre><code class="language-dart">Provider&lt;Country&gt;( create: (_) =&gt; Country('England'), child: Provider&lt;City&gt;( create: (_) =&gt; City('London'), child: ..., ), ), </code></pre> <h4 id="can-i-consume-an-interface-and-provide-an-implementation">Can I consume an interface and provide an implementation?</h4> <p>Yes, a type hint must be given to the compiler to indicate the interface will be consumed, with the implementation provided in create.</p> <pre><code class="language-dart">abstract class ProviderInterface with ChangeNotifier { ... } class ProviderImplementation with ChangeNotifier implements ProviderInterface { ... } class Foo extends StatelessWidget { @override build(context) { final provider = Provider.of&lt;ProviderInterface&gt;(context); return ... } } ChangeNotifierProvider&lt;ProviderInterface&gt;( create: (_) =&gt; ProviderImplementation(), child: Foo(), ), </code></pre> <h3 class="hash-header" id="existing-providers">Existing providers <a href="#existing-providers" class="hash-link">#</a></h3> <p><code>provider</code> exposes a few different kinds of "provider" for different types of objects.</p> <p>The complete list of all the objects available is <a href="https://pub.dev/documentation/provider/latest/provider/provider-library.html">here</a></p> <table> <thead> <tr> <th>name</th> <th>description</th> </tr> </thead> <tbody> <tr> <td><a href="https://pub.dartlang.org/documentation/provider/latest/provider/Provider-class.html" rel="ugc">Provider</a></td> <td>The most basic form of provider. It takes a value and exposes it, whatever the value is.</td> </tr> <tr> <td><a href="https://pub.dartlang.org/documentation/provider/latest/provider/ListenableProvider-class.html" rel="ugc">ListenableProvider</a></td> <td>A 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.</td> </tr> <tr> <td><a href="https://pub.dartlang.org/documentation/provider/latest/provider/ChangeNotifierProvider-class.html" rel="ugc">ChangeNotifierProvider</a></td> <td>A specification of ListenableProvider for ChangeNotifier. It will automatically call <code>ChangeNotifier.dispose</code> when needed.</td> </tr> <tr> <td><a href="https://pub.dartlang.org/documentation/provider/latest/provider/ValueListenableProvider-class.html" rel="ugc">ValueListenableProvider</a></td> <td>Listen to a ValueListenable and only expose <code>ValueListenable.value</code>.</td> </tr> <tr> <td><a href="https://pub.dartlang.org/documentation/provider/latest/provider/StreamProvider-class.html" rel="ugc">StreamProvider</a></td> <td>Listen to a Stream and expose the latest value emitted.</td> </tr> <tr> <td><a href="https://pub.dartlang.org/documentation/provider/latest/provider/FutureProvider-class.html" rel="ugc">FutureProvider</a></td> <td>Takes a <code>Future</code> and updates dependents when the future completes.</td> </tr> </tbody> </table> <h3 class="hash-header" id="my-application-throws-a-stackoverflowerror-because-i-have-too-many-providers-what-can-i-do">My application throws a StackOverflowError because I have too many providers, what can I do? <a href="#my-application-throws-a-stackoverflowerror-because-i-have-too-many-providers-what-can-i-do" class="hash-link">#</a></h3> <p>If you have a very large number of providers (150+), it is possible that some devices will throw a <code>StackOverflowError</code> because you end-up building too many widgets at once.</p> <p>In this situation, you have a few solutions:</p> <ul> <li> <p>If your application has a splash-screen, try mounting your providers over time instead of all at once.</p> <p>You could do:</p> <pre><code class="language-dart">MultiProvider( providers: [ if (step1) ...[ &lt;lots of providers&gt;, ], if (step2) ...[ &lt;some more providers&gt; ] ], ) </code></pre> <p>where during your splash screen animation, you would do:</p> <pre><code class="language-dart">bool step1 = false; bool step2 = false; @override initState() { super.initState(); Future(() { setState(() =&gt; step1 = true); Future(() { setState(() =&gt; step2 = true); }); }); } </code></pre> </li> <li> <p>Consider opting out of using <code>MultiProvider</code>. <code>MultiProvider</code> works by adding a widget between every providers. Not using <code>MultiProvider</code> can increase the limit before a <code>StackOverflowError</code> is reached.</p> </li> </ul> <h2 class="hash-header" id="sponsors">Sponsors <a href="#sponsors" class="hash-link">#</a></h2> <p align="center"> <a href="https://raw.githubusercontent.com/rrousselGit/freezed/master/sponsorkit/sponsors.svg" rel="ugc"> <img src="https://raw.githubusercontent.com/rrousselGit/freezed/master/sponsorkit/sponsors.svg"> </a> </p> </section></div></div></div><aside class="detail-info-box"><a class="packages-scores" href="/packages/provider/score"><div class="packages-score packages-score-like"><div class="packages-score-value -has-value"><span class="packages-score-value-number">10382</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">likes</div></div><div class="packages-score packages-score-health"><div class="packages-score-value -has-value"><span class="packages-score-value-number">160</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">pub points</div></div><div class="packages-score packages-score-popularity"><div class="packages-score-value -has-value"><span class="packages-score-value-number">100</span><span class="packages-score-value-sign">%</span></div><div class="packages-score-label">popularity</div></div></a><h3 class="title">Publisher</h3><p><a href="/publishers/dash-overflow.net"><img class="-pub-publisher-shield filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-verified.svg" alt="verified publisher" width="14" height="14" title="Published by a pub.dev verified publisher"/>dash-overflow.net</a></p><h3 class="title pkg-infobox-metadata">Metadata</h3><p>A wrapper around InheritedWidget to make them easier to use and more reusable.</p><p><a class="link" href="https://github.com/rrousselGit/provider" rel="ugc">Repository (GitHub)</a><br/><a class="link" href="https://github.com/rrousselGit/provider/issues" rel="ugc">View&#47;report issues</a><br/></p><h3 class="title">Documentation</h3><p><a class="link" href="/documentation/provider/latest/">API reference</a><br/></p><h3 class="title">License</h3><p><img class="inline-icon-img filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-balance.svg" alt="" width="14" height="14" role="presentation"/>MIT (<a href="/packages/provider/license">license</a>)</p><h3 class="title">Dependencies</h3><p><a href="/packages/collection" title="^1.15.0">collection</a>, <a href="https://api.flutter.dev/">flutter</a>, <a href="/packages/nested" title="^1.0.0">nested</a></p><h3 class="title">More</h3><p><a href="/packages?q=dependency%3Aprovider" rel="nofollow">Packages that depend on provider</a></p></aside></div><script type="application/ld+json">{"@context":"http\u003a\u002f\u002fschema.org","@type":"SoftwareSourceCode","name":"provider","version":"6.1.2","description":"provider - A wrapper around InheritedWidget to make them easier to use and more reusable.","url":"https\u003a\u002f\u002fpub.dev\u002fpackages\u002fprovider","dateCreated":"2018-10-19T12\u003a25\u003a31.400368Z","dateModified":"2024-02-28T17\u003a09\u003a34.887284Z","programmingLanguage":"Dart","image":"https\u003a\u002f\u002fpub.dev\u002fstatic\u002fimg\u002fpub-dev-icon-cover-image.png","license":"https\u003a\u002f\u002fpub.dev\u002fpackages\u002fprovider\u002flicense"}</script></div><div class="detail-metadata"><h3 class="detail-metadata-title"><span class="detail-metadata-toggle">←</span> Metadata</h3><div class="detail-info-box"><a class="packages-scores" href="/packages/provider/score"><div class="packages-score packages-score-like"><div class="packages-score-value -has-value"><span class="packages-score-value-number">10382</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">likes</div></div><div class="packages-score packages-score-health"><div class="packages-score-value -has-value"><span class="packages-score-value-number">160</span><span class="packages-score-value-sign"></span></div><div class="packages-score-label">pub points</div></div><div class="packages-score packages-score-popularity"><div class="packages-score-value -has-value"><span class="packages-score-value-number">100</span><span class="packages-score-value-sign">%</span></div><div class="packages-score-label">popularity</div></div></a><h3 class="title">Publisher</h3><p><a href="/publishers/dash-overflow.net"><img class="-pub-publisher-shield filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-verified.svg" alt="verified publisher" width="14" height="14" title="Published by a pub.dev verified publisher"/>dash-overflow.net</a></p><h3 class="title pkg-infobox-metadata">Metadata</h3><p>A wrapper around InheritedWidget to make them easier to use and more reusable.</p><p><a class="link" href="https://github.com/rrousselGit/provider" rel="ugc">Repository (GitHub)</a><br/><a class="link" href="https://github.com/rrousselGit/provider/issues" rel="ugc">View&#47;report issues</a><br/></p><h3 class="title">Documentation</h3><p><a class="link" href="/documentation/provider/latest/">API reference</a><br/></p><h3 class="title">License</h3><p><img class="inline-icon-img filter-invert-on-dark" src="/static/hash-o6oemknr/img/material-icon-balance.svg" alt="" width="14" height="14" role="presentation"/>MIT (<a href="/packages/provider/license">license</a>)</p><h3 class="title">Dependencies</h3><p><a href="/packages/collection" title="^1.15.0">collection</a>, <a href="https://api.flutter.dev/">flutter</a>, <a href="/packages/nested" title="^1.0.0">nested</a></p><h3 class="title">More</h3><p><a href="/packages?q=dependency%3Aprovider" rel="nofollow">Packages that depend on provider</a></p></div><p class="detail-lead-back"><a class="detail-metadata-toggle">Back</a></p></div><div id="-screenshot-carousel" class="carousel"><fab id="-carousel-prev" class="mdc-fab carousel-prev carousel-nav" data-mdc-auto-init="MDCRipple" title="Previous" data-ga-click-event="screenshot-carousel-prev-click" tabindex="0"><div class="mdc-fab__ripple"></div><img class="mdc-fab__icon" src="/static/hash-o6oemknr/img/keyboard_arrow_left.svg" alt="previous" width="24" height="24" aria-hidden="true"/></fab><div id="-image-container" class="image-container"></div><fab id="-carousel-next" class="mdc-fab carousel-next carousel-nav" data-mdc-auto-init="MDCRipple" title="Next" data-ga-click-event="screenshot-carousel-next-click" tabindex="0"><div class="mdc-fab__ripple"></div><img class="mdc-fab__icon" src="/static/hash-o6oemknr/img/keyboard_arrow_right.svg" alt="next" width="24" height="24" aria-hidden="true"/></fab><p id="-screenshot-description" class="screenshot-description"></p></div></main><footer class="site-footer"><a class="link" href="https://dart.dev/">Dart language</a><a class="link sep" href="/report?subject=package%3Aprovider&amp;url=https%3A%2F%2Fpub.dev%2Fpackages%2Fprovider">Report package</a><a class="link sep" href="/policy">Policy</a><a class="link sep" href="https://www.google.com/intl/en/policies/terms/">Terms</a><a class="link sep" href="https://developers.google.com/terms/">API Terms</a><a class="link sep" href="/security">Security</a><a class="link sep" href="https://www.google.com/intl/en/policies/privacy/">Privacy</a><a class="link sep" href="/help">Help</a><a class="link icon sep" href="/feed.atom"><img class="inline-icon" src="/static/hash-o6oemknr/img/rss-feed-icon.svg" alt="RSS" width="20" height="20" title="RSS/atom feed"/></a><a class="link icon github_issue" href="https://github.com/dart-lang/pub-dev/issues/new"><img class="inline-icon" src="/static/hash-o6oemknr/img/bug-report-white-96px.png" alt="bug report" width="20" height="20" title="Report an issue with this site"/></a></footer><script src="/static/hash-o6oemknr/highlight/highlight-with-init.js" defer="defer"></script></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10