Line data Source code
1 : import 'package:bloc/bloc.dart'; 2 : import 'package:flutter/widgets.dart'; 3 : 4 : import 'bloc_builder.dart'; 5 : import 'bloc_listener.dart'; 6 : 7 : /// {@template bloc_consumer} 8 : /// [BlocConsumer] exposes a [builder] and [listener] in order react to new 9 : /// states. 10 : /// [BlocConsumer] is analogous to a nested `BlocListener` 11 : /// and `BlocBuilder` but reduces the amount of boilerplate needed. 12 : /// [BlocConsumer] should only be used when it is necessary to both rebuild UI 13 : /// and execute other reactions to state changes in the [bloc]. 14 : /// 15 : /// [BlocConsumer] takes a required `BlocWidgetBuilder` 16 : /// and `BlocWidgetListener` and an optional [bloc], 17 : /// `BlocBuilderCondition`, and `BlocListenerCondition`. 18 : /// 19 : /// If the [bloc] parameter is omitted, [BlocConsumer] will automatically 20 : /// perform a lookup using `BlocProvider` and the current `BuildContext`. 21 : /// 22 : /// ```dart 23 : /// BlocConsumer<BlocA, BlocAState>( 24 : /// listener: (context, state) { 25 : /// // do stuff here based on BlocA's state 26 : /// }, 27 : /// builder: (context, state) { 28 : /// // return widget here based on BlocA's state 29 : /// } 30 : /// ) 31 : /// ``` 32 : /// 33 : /// An optional [listenWhen] and [buildWhen] can be implemented for more 34 : /// granular control over when [listener] and [builder] are called. 35 : /// The [listenWhen] and [buildWhen] will be invoked on each [bloc] `state` 36 : /// change. 37 : /// They each take the previous `state` and current `state` and must return 38 : /// a [bool] which determines whether or not the [builder] and/or [listener] 39 : /// function will be invoked. 40 : /// The previous `state` will be initialized to the `state` of the [bloc] when 41 : /// the [BlocConsumer] is initialized. 42 : /// [listenWhen] and [buildWhen] are optional and if they aren't implemented, 43 : /// they will default to `true`. 44 : /// 45 : /// ```dart 46 : /// BlocConsumer<BlocA, BlocAState>( 47 : /// listenWhen: (previous, current) { 48 : /// // return true/false to determine whether or not 49 : /// // to invoke listener with state 50 : /// }, 51 : /// listener: (context, state) { 52 : /// // do stuff here based on BlocA's state 53 : /// }, 54 : /// buildWhen: (previous, current) { 55 : /// // return true/false to determine whether or not 56 : /// // to rebuild the widget with state 57 : /// }, 58 : /// builder: (context, state) { 59 : /// // return widget here based on BlocA's state 60 : /// } 61 : /// ) 62 : /// ``` 63 : /// {@endtemplate} 64 : class BlocConsumer<B extends BlocBase<S>, S extends Object> 65 : extends BlocListenerBase<B, S> { 66 : /// The [BlocConsumer] constuctor listen and rebuilds a widget 67 : /// when a `bloc` state change. 68 1 : const BlocConsumer({ 69 : Key? key, 70 : 71 : /// The [bloc] that the [BlocConsumer] will interact with. 72 : /// If omitted, [BlocConsumer] will automatically perform a lookup using 73 : /// `BlocProvider` and the current `BuildContext`. 74 : B? bloc, 75 : BlocListenerCondition<S>? listenWhen, 76 : required BlocWidgetListener<S> listener, 77 : this.buildWhen, 78 : required this.builder, 79 1 : }) : super( 80 : key: key, 81 : bloc: bloc, 82 : listenWhen: listenWhen, 83 : listener: listener, 84 : ); 85 : 86 : /// Takes the previous `state` and the current `state` and is responsible for 87 : /// returning a [bool] which determines whether or not to call [listener] of 88 : /// [BlocConsumer] with the current `state`. 89 : final BlocBuilderCondition<S>? buildWhen; 90 : 91 : /// The [builder] function which will be invoked on each widget build. 92 : /// The [builder] takes the `BuildContext` and current `state` and 93 : /// must return a widget. 94 : /// This is analogous to the [builder] function in [StreamBuilder]. 95 : final BlocWidgetBuilder<S> builder; 96 : 97 : /// Takes the previous `state` and the current `state` and is responsible 98 : /// for returning a [bool] which determines whether or not to trigger 99 : /// [builder] with the current `state`. 100 1 : @override 101 : Widget build(BuildContext context) { 102 1 : final _cubit = $use(); 103 3 : return builder(context, _cubit.state); 104 : } 105 : 106 1 : @override 107 : bool onStateEmitted(BuildContext context, S previous, S state) { 108 1 : super.onStateEmitted(context, previous, state); 109 2 : return buildWhen?.call(previous, state) ?? true; 110 : } 111 : }