1
import 'package:flutter/widgets.dart';
2
import 'package:nested/nested.dart';
3
import 'provider.dart';
4
import 'selector.dart' show Selector;
5

6
/// {@template provider.consumer}
7
/// Obtains [Provider<T>] from its ancestors and passes its value to [builder].
8
///
9
/// The [Consumer] widget doesn't do any fancy work. It just calls [Provider.of]
10
/// in a new widget, and delegates its `build` implementation to [builder].
11
///
12
/// [builder] must not be null and may be called multiple times (such as when
13
/// the provided value change).
14
///
15
/// The [Consumer] widget has two main purposes:
16
///
17
/// * It allows obtaining a value from a provider when we don't have a
18
///   [BuildContext] that is a descendant of said provider, and therefore
19
///   cannot use [Provider.of].
20
///
21
/// This scenario typically happens when the widget that creates the provider
22
/// is also one of its consumers, like in the following example:
23
///
24
/// ```dart
25
/// @override
26
/// Widget build(BuildContext context) {
27
///   return ChangeNotifierProvider(
28
///     create: (_) => Foo(),
29
///     child: Text(Provider.of<Foo>(context).value),
30
///   );
31
/// }
32
/// ```
33
///
34
/// This example will throw a [ProviderNotFoundException], because [Provider.of]
35
/// is called with a [BuildContext] that is an ancestor of the provider.
36
///
37
/// Instead, we can use the [Consumer] widget, that will call [Provider.of]
38
/// with its own [BuildContext].
39
///
40
/// Using [Consumer], the previous example will become:
41
///
42
/// ```dart
43
/// @override
44
/// Widget build(BuildContext context) {
45
///   return ChangeNotifierProvider(
46
///     create: (_) => Foo(),
47
///     child: Consumer<Foo>(
48
///       builder: (_, foo, __) => Text(foo.value),
49
///     },
50
///   );
51
/// }
52
/// ```
53
///
54
/// This won't throw a [ProviderNotFoundException] and will correctly build the
55
/// [Text]. It will also update the [Text] whenever the value `foo` changes.
56
///
57
///
58
/// * It helps with performance optimisation by providing more granular rebuilds.
59
///
60
/// Unless `listen: false` is passed to [Provider.of], the widget
61
/// associated with the [BuildContext] passed to [Provider.of] will rebuild
62
/// whenever the obtained value changes. This is the expected behavior,
63
/// but sometimes it may rebuild more widgets than needed.
64
///
65
/// Here's an example:
66
///
67
/// ```dart
68
///  @override
69
///  Widget build(BuildContext context) {
70
///    return FooWidget(
71
///      child: BarWidget(
72
///        bar: Provider.of<Bar>(context),
73
///      ),
74
///    );
75
///  }
76
/// ```
77
///
78
/// In the above code, only `BarWidget` depends on the value returned by
79
/// [Provider.of]. But when `Bar` changes, then both `BarWidget` _and_
80
/// `FooWidget` will rebuild.
81
///
82
/// Ideally, only `BarWidget` should be rebuilt. One
83
/// solution to achieve that is to use [Consumer].
84
///
85
/// To do so, we will wrap _only_ the widgets that depends on a provider into
86
/// a [Consumer]:
87
///
88
/// ```dart
89
///  @override
90
///  Widget build(BuildContext context) {
91
///    return FooWidget(
92
///      child: Consumer<Bar>(
93
///        builder: (_, bar, __) => BarWidget(bar: bar),
94
///      ),
95
///    );
96
///  }
97
/// ```
98
///
99
/// In this situation, if `Bar` were to update, only `BarWidget` would rebuild.
100
///
101
/// But what if it was `FooWidget` that depended on a provider? Example:
102
///
103
/// ```dart
104
///  @override
105
///  Widget build(BuildContext context) {
106
///    return FooWidget(
107
///      foo: Provider.of<Foo>(context),
108
///      child: BarWidget(),
109
///    );
110
///  }
111
/// ```
112
///
113
/// Using [Consumer], we can handle this kind of scenario using the optional
114
/// `child` argument:
115
///
116
/// ```dart
117
///  @override
118
///  Widget build(BuildContext context) {
119
///    return Consumer<Foo>(
120
///      builder: (_, foo, child) => FooWidget(foo: foo, child: child),
121
///      child: BarWidget(),
122
///    );
123
///  }
124
/// ```
125
///
126
/// In that example, `BarWidget` is built outside of [builder]. Then, the
127
/// `BarWidget` instance is passed to [builder] as the last parameter.
128
///
129
/// This means that when [builder] is called again with new values, a new
130
/// instance of `BarWidget` will not be created.
131
/// This lets Flutter know that it doesn't have to rebuild `BarWidget`.
132
/// Therefore in such a configuration, only `FooWidget` will rebuild
133
/// if `Foo` changes.
134
///
135
/// ## Note:
136
///
137
/// The [Consumer] widget can also be used inside [MultiProvider]. To do so, it
138
/// must return the `child` passed to [builder] in the widget tree it creates.
139
///
140
/// ```dart
141
/// MultiProvider(
142
///   providers: [
143
///     Provider(create: (_) => Foo()),
144
///     Consumer<Foo>(
145
///       builder: (context, foo, child) =>
146
///         Provider.value(value: foo.bar, child: child),
147
///     )
148
///   ],
149
/// );
150
/// ```
151
///
152
/// See also:
153
///   * [Selector], a [Consumer] that can filter updates.
154
/// {@endtemplate}
155
class Consumer<T> extends SingleChildStatelessWidget {
156
  /// {@template provider.consumer.constructor}
157
  /// Consumes a [Provider<T>]
158
  /// {@endtemplate}
159 3
  Consumer({
160
    Key key,
161
    @required this.builder,
162
    Widget child,
163 3
  })  : assert(builder != null),
164 3
        super(key: key, child: child);
165

166
  /// {@template provider.consumer.builder}
167
  /// Build a widget tree based on the value from a [Provider<T>].
168
  ///
169
  /// Must not be `null`.
170
  /// {@endtemplate}
171
  final Widget Function(BuildContext context, T value, Widget child) builder;
172

173 3
  @override
174
  Widget buildWithChild(BuildContext context, Widget child) {
175 3
    return builder(
176
      context,
177 3
      Provider.of<T>(context),
178
      child,
179
    );
180
  }
181
}
182

183
/// {@macro provider.consumer}
184
class Consumer2<A, B> extends SingleChildStatelessWidget {
185
  /// {@macro provider.consumer.constructor}
186 3
  Consumer2({
187
    Key key,
188
    @required this.builder,
189
    Widget child,
190 3
  })  : assert(builder != null),
191 3
        super(key: key, child: child);
192

193
  /// {@macro provider.consumer.builder}
194
  final Widget Function(BuildContext context, A value, B value2, Widget child)
195
      builder;
196

197 3
  @override
198
  Widget buildWithChild(BuildContext context, Widget child) {
199 3
    return builder(
200
      context,
201 3
      Provider.of<A>(context),
202 3
      Provider.of<B>(context),
203
      child,
204
    );
205
  }
206
}
207

208
/// {@macro provider.consumer}
209
class Consumer3<A, B, C> extends SingleChildStatelessWidget {
210
  /// {@macro provider.consumer.constructor}
211 3
  Consumer3({
212
    Key key,
213
    @required this.builder,
214
    Widget child,
215 3
  })  : assert(builder != null),
216 3
        super(key: key, child: child);
217

218
  /// {@macro provider.consumer.builder}
219
  final Widget Function(
220
      BuildContext context, A value, B value2, C value3, Widget child) builder;
221

222 3
  @override
223
  Widget buildWithChild(BuildContext context, Widget child) {
224 3
    return builder(
225
      context,
226 3
      Provider.of<A>(context),
227 3
      Provider.of<B>(context),
228 3
      Provider.of<C>(context),
229
      child,
230
    );
231
  }
232
}
233

234
/// {@macro provider.consumer}
235
class Consumer4<A, B, C, D> extends SingleChildStatelessWidget {
236
  /// {@macro provider.consumer.constructor}
237 3
  Consumer4({
238
    Key key,
239
    @required this.builder,
240
    Widget child,
241 3
  })  : assert(builder != null),
242 3
        super(key: key, child: child);
243

244
  /// {@macro provider.consumer.builder}
245
  final Widget Function(
246
    BuildContext context,
247
    A value,
248
    B value2,
249
    C value3,
250
    D value4,
251
    Widget child,
252
  ) builder;
253 3
  @override
254
  Widget buildWithChild(BuildContext context, Widget child) {
255 3
    return builder(
256
      context,
257 3
      Provider.of<A>(context),
258 3
      Provider.of<B>(context),
259 3
      Provider.of<C>(context),
260 3
      Provider.of<D>(context),
261
      child,
262
    );
263
  }
264
}
265

266
/// {@macro provider.consumer}
267
class Consumer5<A, B, C, D, E> extends SingleChildStatelessWidget {
268
  /// {@macro provider.consumer.constructor}
269 3
  Consumer5({
270
    Key key,
271
    @required this.builder,
272
    Widget child,
273 3
  })  : assert(builder != null),
274 3
        super(key: key, child: child);
275

276
  /// {@macro provider.consumer.builder}
277
  final Widget Function(
278
    BuildContext context,
279
    A value,
280
    B value2,
281
    C value3,
282
    D value4,
283
    E value5,
284
    Widget child,
285
  ) builder;
286

287 3
  @override
288
  Widget buildWithChild(BuildContext context, Widget child) {
289 3
    return builder(
290
      context,
291 3
      Provider.of<A>(context),
292 3
      Provider.of<B>(context),
293 3
      Provider.of<C>(context),
294 3
      Provider.of<D>(context),
295 3
      Provider.of<E>(context),
296
      child,
297
    );
298
  }
299
}
300

301
/// {@macro provider.consumer}
302
class Consumer6<A, B, C, D, E, F> extends SingleChildStatelessWidget {
303
  /// {@macro provider.consumer.constructor}
304 3
  Consumer6({
305
    Key key,
306
    @required this.builder,
307
    Widget child,
308 3
  })  : assert(builder != null),
309 3
        super(key: key, child: child);
310

311
  /// {@macro provider.consumer.builder}
312
  final Widget Function(
313
    BuildContext context,
314
    A value,
315
    B value2,
316
    C value3,
317
    D value4,
318
    E value5,
319
    F value6,
320
    Widget child,
321
  ) builder;
322

323 3
  @override
324
  Widget buildWithChild(BuildContext context, Widget child) {
325 3
    return builder(
326
      context,
327 3
      Provider.of<A>(context),
328 3
      Provider.of<B>(context),
329 3
      Provider.of<C>(context),
330 3
      Provider.of<D>(context),
331 3
      Provider.of<E>(context),
332 3
      Provider.of<F>(context),
333
      child,
334
    );
335
  }
336
}

Read our documentation on viewing source code .

Loading