1
import 'package:flutter/widgets.dart';
2

3
import 'listenable_provider.dart';
4
import 'provider.dart';
5
import 'proxy_provider.dart';
6

7
/// Listens to a [ChangeNotifier], expose it to its descendants and rebuilds
8
/// dependents whenever [ChangeNotifier.notifyListeners] is called.
9
///
10
/// Depending on wether you want to **create** or **reuse** a [ChangeNotifier],
11
/// you will want to use different constructors.
12
///
13
/// ## Creating a [ChangeNotifier]:
14
///
15
/// To create a value, use the default constructor. Creating the instance
16
/// inside `build` using `ChangeNotifierProvider.value` will lead to memory
17
/// leaks and potentially undesired side-effects.
18
///
19
/// See [this stackoverflow answer](https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build)
20
/// which explains in further details why using the `.value` constructor to
21
/// create values is undesired.
22
///
23
/// - **DO** create a new [ChangeNotifier] inside `create`.
24
///
25
/// ```dart
26
/// ChangeNotifierProvider(
27
///   create: (_) => new MyChangeNotifier(),
28
///   child: ...
29
/// )
30
/// ```
31
///
32
/// - **DON'T** use `ChangeNotifierProvider.value` to create your
33
///   [ChangeNotifier].
34
///
35
/// ```dart
36
/// ChangeNotifierProvider.value(
37
///   value: new MyChangeNotifier(),
38
///   child: ...
39
/// )
40
/// ```
41
///
42
/// - **DON'T** create your [ChangeNotifier] from variables that can change over
43
///   the time.
44
///
45
///   In such situation, your [ChangeNotifier] would never be updated when the
46
///   value changes.
47
///
48
/// ```dart
49
/// int count;
50
///
51
/// ChangeNotifierProvider(
52
///   create: (_) => new MyChangeNotifier(count),
53
///   child: ...
54
/// )
55
/// ```
56
///
57
/// If you want to pass variables to your [ChangeNotifier], consider using
58
/// [ChangeNotifierProxyProvider].
59
///
60
/// ## Reusing an existing instance of [ChangeNotifier]:
61
///
62
/// If you already have an instance of [ChangeNotifier] and want to expose it,
63
/// you should use [ChangeNotifierProvider.value] instead of the default
64
/// constructor.
65
///
66
/// Failing to do so may dispose the [ChangeNotifier] when it is still in use.
67
///
68
/// - **DO** use [ChangeNotifierProvider.value] to provide an existing
69
///   [ChangeNotifier].
70
///
71
/// ```dart
72
/// MyChangeNotifier variable;
73
///
74
/// ChangeNotifierProvider.value(
75
///   value: variable,
76
///   child: ...
77
/// )
78
/// ```
79
///
80
/// - **DON'T** reuse an existing [ChangeNotifier] using the default constructor
81
///
82
/// ```dart
83
/// MyChangeNotifier variable;
84
///
85
/// ChangeNotifierProvider(
86
///   create: (_) => variable,
87
///   child: ...
88
/// )
89
/// ```
90
///
91
/// See also:
92
///
93
///   * [ChangeNotifier], which is listened by [ChangeNotifierProvider].
94
///   * [ChangeNotifierProxyProvider], to create and provide a [ChangeNotifier]
95
///     of variables from other providers.
96
///   * [ListenableProvider], similar to [ChangeNotifierProvider] but works with
97
///     any [Listenable].
98
class ChangeNotifierProvider<T extends ChangeNotifier>
99
    extends ListenableProvider<T> {
100 3
  static void _dispose(BuildContext context, ChangeNotifier notifier) {
101 3
    notifier?.dispose();
102
  }
103

104
  /// Creates a [ChangeNotifier] using `create` and automatically
105
  /// dispose it when [ChangeNotifierProvider] is removed from the widget tree.
106
  ///
107
  /// `create` must not be `null`.
108 3
  ChangeNotifierProvider({
109
    Key key,
110
    @required Create<T> create,
111
    bool lazy,
112
    TransitionBuilder builder,
113
    Widget child,
114 3
  }) : super(
115
          key: key,
116
          create: create,
117
          dispose: _dispose,
118
          lazy: lazy,
119
          builder: builder,
120
          child: child,
121
        );
122

123
  /// Provides an existing [ChangeNotifier].
124 3
  ChangeNotifierProvider.value({
125
    Key key,
126
    @required T value,
127
    TransitionBuilder builder,
128
    Widget child,
129 3
  }) : super.value(
130
          key: key,
131
          builder: builder,
132
          value: value,
133
          child: child,
134
        );
135
}
136

137
/// {@template provider.changenotifierproxyprovider}
138
/// A [ChangeNotifierProvider] that builds and synchronizes a [ChangeNotifier]
139
/// with external values.
140
///
141
/// To understand better this variation of [ChangeNotifierProvider], we can
142
/// look into the following code using the original provider:
143
///
144
/// ```dart
145
/// ChangeNotifierProvider(
146
///   create: (context) {
147
///     return MyChangeNotifier(
148
///       myModel: Provider.of<MyModel>(context, listen: false),
149
///     );
150
///   },
151
///   child: ...
152
/// )
153
/// ```
154
///
155
/// In this example, we built a `MyChangeNotifier` from a value coming from
156
/// another provider: `MyModel`.
157
///
158
/// This works as long as `MyModel` never changes. But if it somehow updates,
159
/// then our [ChangeNotifier] will never update accordingly.
160
///
161
/// To solve this issue, we could instead use this class, like so:
162
///
163
/// ```dart
164
/// ChangeNotifierProxyProvider<MyModel, MyChangeNotifier>(
165
///   create: (_) => MyChangeNotifier(),
166
///   update: (_, myModel, myNotifier) => myNotifier
167
///     ..update(myModel),
168
///   child: ...
169
/// );
170
/// ```
171
///
172
/// In that situation, if `MyModel` were to update, then `MyChangeNotifier` will
173
/// be able to update accordingly.
174
///
175
/// Notice how `MyChangeNotifier` doesn't receive `MyModel` in its constructor
176
/// anymore. It is now passed through a custom setter/method instead.
177
///
178
/// A typical implementation of such `MyChangeNotifier` could be:
179
///
180
/// ```dart
181
/// class MyChangeNotifier with ChangeNotifier {
182
///   void update(MyModel myModel) {
183
///     // Do some custom work based on myModel that may call `notifyListeners`
184
///   }
185
/// }
186
/// ```
187
///
188
/// - **DON'T** create the [ChangeNotifier] inside `update` directly.
189
///
190
///   This will cause your state to be lost when one of the values used updates.
191
///   It will also cause unnecessary overhead because it will dispose the
192
///   previous notifier, then subscribes to the new one.
193
///
194
///  Instead reuse the previous instance, and update some properties or call
195
///  some methods.
196
///
197
/// ```dart
198
/// ChangeNotifierProxyProvider<MyModel, MyChangeNotifier>(
199
///   // may cause the state to be destroyed involuntarily
200
///   update: (_, myModel, myNotifier) => MyChangeNotifier(myModel: myModel),
201
///   child: ...
202
/// );
203
/// ```
204
///
205
/// - **PREFER** using [ProxyProvider] when possible.
206
///
207
///   If the created object is only a combination of other objects, without
208
///   http calls or similar side-effects, then it is likely that an immutable
209
///   object built using [ProxyProvider] will work.
210
/// {@endtemplate}
211
class ChangeNotifierProxyProvider<T, R extends ChangeNotifier>
212
    extends ListenableProxyProvider<T, R> {
213
  /// Initializes [key] for subclasses.
214 3
  ChangeNotifierProxyProvider({
215
    Key key,
216
    @required Create<R> create,
217
    @required ProxyProviderBuilder<T, R> update,
218
    bool lazy,
219
    TransitionBuilder builder,
220
    Widget child,
221 3
  }) : super(
222
          key: key,
223
          create: create,
224
          update: update,
225
          dispose: ChangeNotifierProvider._dispose,
226
          lazy: lazy,
227
          builder: builder,
228
          child: child,
229
        );
230
}
231

232
/// {@macro provider.changenotifierproxyprovider}
233
class ChangeNotifierProxyProvider0<R extends ChangeNotifier>
234
    extends ListenableProxyProvider0<R> {
235
  /// Initializes [key] for subclasses.
236 3
  ChangeNotifierProxyProvider0({
237
    Key key,
238
    @required Create<R> create,
239
    @required R Function(BuildContext, R value) update,
240
    bool lazy,
241
    TransitionBuilder builder,
242
    Widget child,
243 3
  }) : super(
244
          key: key,
245
          create: create,
246
          update: update,
247
          dispose: ChangeNotifierProvider._dispose,
248
          lazy: lazy,
249
          builder: builder,
250
          child: child,
251
        );
252
}
253

254
/// {@macro provider.changenotifierproxyprovider}
255
class ChangeNotifierProxyProvider2<T, T2, R extends ChangeNotifier>
256
    extends ListenableProxyProvider2<T, T2, R> {
257
  /// Initializes [key] for subclasses.
258 3
  ChangeNotifierProxyProvider2({
259
    Key key,
260
    @required Create<R> create,
261
    @required ProxyProviderBuilder2<T, T2, R> update,
262
    bool lazy,
263
    TransitionBuilder builder,
264
    Widget child,
265 3
  }) : super(
266
          key: key,
267
          create: create,
268
          update: update,
269
          dispose: ChangeNotifierProvider._dispose,
270
          lazy: lazy,
271
          builder: builder,
272
          child: child,
273
        );
274
}
275

276
/// {@macro provider.changenotifierproxyprovider}
277
class ChangeNotifierProxyProvider3<T, T2, T3, R extends ChangeNotifier>
278
    extends ListenableProxyProvider3<T, T2, T3, R> {
279
  /// Initializes [key] for subclasses.
280 3
  ChangeNotifierProxyProvider3({
281
    Key key,
282
    @required Create<R> create,
283
    @required ProxyProviderBuilder3<T, T2, T3, R> update,
284
    bool lazy,
285
    TransitionBuilder builder,
286
    Widget child,
287 3
  }) : super(
288
          key: key,
289
          create: create,
290
          update: update,
291
          dispose: ChangeNotifierProvider._dispose,
292
          lazy: lazy,
293
          builder: builder,
294
          child: child,
295
        );
296
}
297

298
/// {@macro provider.changenotifierproxyprovider}
299
class ChangeNotifierProxyProvider4<T, T2, T3, T4, R extends ChangeNotifier>
300
    extends ListenableProxyProvider4<T, T2, T3, T4, R> {
301
  /// Initializes [key] for subclasses.
302 3
  ChangeNotifierProxyProvider4({
303
    Key key,
304
    @required Create<R> create,
305
    @required ProxyProviderBuilder4<T, T2, T3, T4, R> update,
306
    bool lazy,
307
    TransitionBuilder builder,
308
    Widget child,
309 3
  }) : super(
310
          key: key,
311
          create: create,
312
          update: update,
313
          dispose: ChangeNotifierProvider._dispose,
314
          lazy: lazy,
315
          builder: builder,
316
          child: child,
317
        );
318
}
319

320
/// {@macro provider.changenotifierproxyprovider}
321
class ChangeNotifierProxyProvider5<T, T2, T3, T4, T5, R extends ChangeNotifier>
322
    extends ListenableProxyProvider5<T, T2, T3, T4, T5, R> {
323
  /// Initializes [key] for subclasses.
324 3
  ChangeNotifierProxyProvider5({
325
    Key key,
326
    @required Create<R> create,
327
    @required ProxyProviderBuilder5<T, T2, T3, T4, T5, R> update,
328
    bool lazy,
329
    TransitionBuilder builder,
330
    Widget child,
331 3
  }) : super(
332
          key: key,
333
          create: create,
334
          update: update,
335
          dispose: ChangeNotifierProvider._dispose,
336
          lazy: lazy,
337
          builder: builder,
338
          child: child,
339
        );
340
}
341

342
/// {@macro provider.changenotifierproxyprovider}
343
class ChangeNotifierProxyProvider6<T, T2, T3, T4, T5, T6,
344
        R extends ChangeNotifier>
345
    extends ListenableProxyProvider6<T, T2, T3, T4, T5, T6, R> {
346
  /// Initializes [key] for subclasses.
347 3
  ChangeNotifierProxyProvider6({
348
    Key key,
349
    @required Create<R> create,
350
    @required ProxyProviderBuilder6<T, T2, T3, T4, T5, T6, R> update,
351
    bool lazy,
352
    TransitionBuilder builder,
353
    Widget child,
354 3
  }) : super(
355
          key: key,
356
          create: create,
357
          update: update,
358
          dispose: ChangeNotifierProvider._dispose,
359
          lazy: lazy,
360
          builder: builder,
361
          child: child,
362
        );
363
}

Read our documentation on viewing source code .

Loading