Skip to content

ReactterConsumer

The ReactterConsumer widget obtains the dependency provided by the closest ReactterProvider widget and rebuilds itself whenever there are changes in the dependency or any defined states.

Syntax

ReactterConsumer<T>({
Key? key,
String? id,
Widget? child,
bool listenAll = false,
List<ReactterState> listenStates(
T instance,
),
required Widget builder(
BuildContext context,
T instance,
Widget? child,
),
})

Properties

  • key: An optional Key to use for identifying the widget.
  • id: An optional identifier for the dependency. If omitted, the dependency will be located by its type( T ).
  • child: An optional Widget that is independent of the ReactterConsumer . If defined, it is passed to the builder function if it is defined.
  • listenAll: A boolean that determines whether to listen to all states provided by the T dependency. If set to true , the listenStates function is ignored. The default value is false .
  • listenStates : A function that returns a list of state( ReactterState ) to listen to. It takes the instance of the T dependency as an åargument. If omitted, the listenAll property is checked.
  • builder : A function that builds a widget depending on the ReactterConsumer . It receives the following arguments:
    • context: The BuildContext of the widget. A handle to the location of ReactterConsumer in the widget tree.
    • instance: The instance of T dependency provided by the closest ReactterProvider widget.
    • child: The child widget passed to the ReactterConsumer widget.

Usage

Basic Usage

To use the ReactterConsumer widget, you need to provide the T dependency using the ReactterProvider widget.

Here’s an example of how to use it:

counter_controller.dart
14 collapsed lines
1
import 'package:reactter/reactter.dart';
2
3
class CounterController {
4
// Create a reactive state using the `Signal` class
5
final count = Signal(0);
6
7
void increment() {
8
count.value++;
9
}
10
11
void decrement() {
12
count.value--;
13
}
14
}
counter_view.dart
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Provides the `CounterController` dependency to the widget tree
11
return ReactterProvider<CounterController>(
12
() => CounterController(),
13
child: Scaffold(
14
appBar: AppBar(
15
title: const Text("Counter"),
16
),
17
body: const Center(
18
child: Counter(),
19
),
20
),
21
);
22
}
23
}
24
25
class Counter extends StatelessWidget {
26
const Counter({Key? key}) : super(key: key);
27
28
Widget build(BuildContext context) {
29
// Locales the `CounterController` dependency
30
return ReactterConsumer<CounterController>(
31
builder: (context, counterController, child) {
32
return Row(
33
mainAxisAlignment: MainAxisAlignment.center,
34
children: [
35
ElevatedButton(
36
onPressed: counterController.decrement,
37
child: const Icon(Icons.remove),
38
),
39
const SizedBox(width: 8),
40
Text("${counterController.count}"),
41
const SizedBox(width: 8),
42
ElevatedButton(
43
onPressed: counterController.increment,
44
child: const Icon(Icons.add),
45
),
46
],
47
);
48
},
49
);
50
}
51
}
main.dart
15 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'counter_view.dart';
3
4
void main() {
5
runApp(MyApp());
6
}
7
8
class MyApp extends StatelessWidget {
9
@override
10
Widget build(BuildContext context) {
11
return MaterialApp(
12
home: CounterView(),
13
);
14
}
15
}

In the example above, the ReactterConsumer widget is used only to access the CounterController dependency within the Counter widget. Consequently, it does not rebuild whenever there are changes in the count state of the CounterController dependency.

Listening to all state

The ReactterConsumer widget can listen to all states provided by the T dependency by setting the listenAll property to true .

Here’s an example of how to use it:

counter_controller.dart
14 collapsed lines
1
import 'package:reactter/reactter.dart';
2
3
class CounterController {
4
// Create a reactive state using the `Signal` class
5
final count = Signal(0);
6
7
void increment() {
8
count.value++;
9
}
10
11
void decrement() {
12
count.value--;
13
}
14
}
counter_view.dart
25 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Provides the `CounterController` dependency to the widget tree
11
return ReactterProvider<CounterController>(
12
// Registers the `CounterController` dependency
13
() => CounterController(),
14
child: Scaffold(
15
appBar: AppBar(
16
title: const Text("Counter"),
17
),
18
body: const Center(
19
child: Counter(),
20
),
21
),
22
);
23
}
24
}
25
26
class Counter extends StatelessWidget {
27
const Counter({Key? key}) : super(key: key);
28
29
Widget build(BuildContext context) {
30
return ReactterConsumer<CounterController>(
31
// Listens to all states provided by the `CounterController` dependency
32
listenAll: true,
33
// Rebuilds whenever there are changes any state of the `CounterController` dependency
34
builder: (context, counterController, child) {
35
return Row(
36
mainAxisAlignment: MainAxisAlignment.center,
37
children: [
38
ElevatedButton(
39
onPressed: counterController.decrement,
40
child: const Icon(Icons.remove),
41
),
42
const SizedBox(width: 8),
43
Text("${counterController.count}"),
44
const SizedBox(width: 8),
45
ElevatedButton(
46
onPressed: counterController.increment,
47
child: const Icon(Icons.add),
48
),
49
],
50
);
51
},
52
);
53
}
54
}
main.dart
15 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'counter_view.dart';
3
4
void main() {
5
runApp(MyApp());
6
}
7
8
class MyApp extends StatelessWidget {
9
@override
10
Widget build(BuildContext context) {
11
return MaterialApp(
12
home: CounterView(),
13
);
14
}
15
}

In the example above, the ReactterConsumer widget will trigger a rebuild of the widget subtree(the Row widget and each of its children) whenever there are changes in any state of the CounterController dependency.

So, that approach lacks performance efficient. It is advisable to optimize by selectively wrapping only the necessary widgets with the ReactterConsumer widget, utilizing either active or non-active listening as appropriate, e.g.:

23
class Counter extends StatelessWidget {
24
const Counter({Key? key}) : super(key: key);
25
26
Widget build(BuildContext context) {
27
return ReactterConsumer<CounterController>(
28
// Listens to all states provided by the `CounterController` dependency
29
listenAll: true,
30
builder: (context, counterController, child) {
31
return Row(
32
mainAxisAlignment: MainAxisAlignment.center,
33
children: [
34
ElevatedButton(
35
onPressed: counterController.decrement,
36
child: const Icon(Icons.remove),
37
),
38
const SizedBox(width: 8),
39
Text("${counterController.count}"),
40
ReactterConsumer<CounterController>(
41
// Listens to all states provided by the `CounterController` dependency
42
listenAll: true,
43
// Rebuilds whenever there are changes any state of the `CounterController` dependency
44
builder: (context, counterController, child) {
45
return Text("${counterController.count}");
46
},
47
),
48
const SizedBox(width: 8),
49
ElevatedButton(
50
onPressed: counterController.increment,
51
child: const Icon(Icons.add),
52
),
53
],
54
);
55
},
56
);
57
}
58
}

Listening to specific states

The ReactterConsumer widget can listen to specific states provided by the T dependency by defining the listenStates property.

Here’s an example of how to use it:

counter_controller.dart
14 collapsed lines
1
import 'package:reactter/reactter.dart';
2
3
class CounterController {
4
// Create a reactive state using the `Signal` class
5
final count = Signal(0);
6
7
void increment() {
8
count.value++;
9
}
10
11
void decrement() {
12
count.value--;
13
}
14
}
counter_view.dart
24 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Provides the `CounterController` dependency to the widget tree
11
return ReactterProvider<CounterController>(
12
() => CounterController(),
13
child: Scaffold(
14
appBar: AppBar(
15
title: const Text("Counter"),
16
),
17
body: const Center(
18
child: const Counter(),
19
),
20
),
21
);
22
}
23
}
24
25
class Counter extends StatelessWidget {
26
const Counter({Key? key}) : super(key: key);
27
28
Widget build(BuildContext context) {+
29
// Locales the `CounterController` dependency
30
return ReactterConsumer<CounterController>(
31
builder: (context, counterController, child) {
32
return Row(
33
mainAxisAlignment: MainAxisAlignment.center,
34
children: [
35
ElevatedButton(
36
onPressed: counterController.decrement,
37
child: const Icon(Icons.remove),
38
),
39
const SizedBox(width: 8),
40
ReactterConsumer<CounterController>(
41
// Listens to the `count` state of the `CounterController` dependency
42
listenStates: (counterController) => [counterController.count],
43
// Rebuilds whenever there are changes in the `count` state of the `CounterController` dependency
44
builder: (context, counterController, child) {
45
return Text("${counterController.count}");
46
},
47
),
48
const SizedBox(width: 8),
49
ElevatedButton(
50
onPressed: counterController.increment,
51
child: const Icon(Icons.add),
52
),
53
],
54
);
55
},
56
);
57
}
58
}
main.dart
15 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'counter_view.dart';
3
4
void main() {
5
runApp(MyApp());
6
}
7
8
class MyApp extends StatelessWidget {
9
@override
10
Widget build(BuildContext context) {
11
return MaterialApp(
12
home: CounterView(),
13
);
14
}
15
}

In the example above, the ReactterConsumer widget will trigger a rebuild of the Text widget whenever there are changes in the count state of the CounterController dependency.

Using id

The ReactterConsumer widget can use the id property to locate the T dependency by its identifier. It is useful when there are multiple instances of the same type of dependency in the widget tree.

Here’s an example of how to use it:

counter_controller.dart
14 collapsed lines
1
import 'package:reactter/reactter.dart';
2
3
class CounterController {
4
// Create a reactive state using the `Signal` class
5
final count = Signal(0);
6
7
void increment() {
8
count.value++;
9
}
10
11
void decrement() {
12
count.value--;
13
}
14
}
counter_view.dart
32 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Provides the `CounterController` dependencies to the widget tree
11
return ReactterProviders(
12
[
13
ReactterProvider(() => CounterController(), id: "counter1"),
14
ReactterProvider(() => CounterController(), id: "counter2"),
15
],
16
child: Scaffold(
17
appBar: AppBar(
18
title: const Text("Counter"),
19
),
20
body: const Center(
21
child: Column(
22
children: [
23
const Counter(id: "counter1"),
24
const Counter(id: "counter2"),
25
],
26
),
27
),
28
),
29
);
30
}
31
}
32
33
class Counter extends StatelessWidget {
34
final String? id;
35
36
const Counter({Key? key, this.id}) : super(key: key);
37
38
Widget build(BuildContext context) {
39
return ReactterConsumer<CounterController>(
40
// Locates the `CounterController` dependency by its identifier
41
id: id,
42
builder: (context, counterController, child) {
43
return Row(
44
mainAxisAlignment: MainAxisAlignment.center,
45
children: [
46
ElevatedButton(
47
onPressed: counterController.decrement,
48
child: const Icon(Icons.remove),
49
),
50
const SizedBox(width: 8),
51
ReactterConsumer<CounterController>(
52
// Locates the `CounterController` dependency by its identifier
53
id: id,
54
// Listens to the `count` state of the `CounterController` dependency
55
listenStates: (counterController) => [counterController.count],
56
// Rebuilds whenever there are changes in the `count` state of the `CounterController` dependency
57
builder: (context, counterController, child) {
58
return Text("${counterController.count}");
59
},
60
),
61
const SizedBox(width: 8),
62
ElevatedButton(
63
onPressed: counterController.increment,
64
child: const Icon(Icons.add),
65
),
66
],
67
);
68
},
69
);
70
}
71
}
main.dart
15 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'counter_view.dart';
3
4
void main() {
5
runApp(MyApp());
6
}
7
8
class MyApp extends StatelessWidget {
9
@override
10
Widget build(BuildContext context) {
11
return MaterialApp(
12
home: CounterView(),
13
);
14
}
15
}

In the example above, the ReactterConsumer widget uses the id property to locate the CounterController dependency by the counter1 and counter2 identifiers.

Using child

The ReactterConsumer widget can accept a child property that is independent of the ReactterConsumer widget. It is useful when you want to provide a widget that does not rebuild when the dependency changes.

Here’s an example of how to use it:

counter_controller.dart
14 collapsed lines
1
import 'package:reactter/reactter.dart';
2
3
class CounterController {
4
// Create a reactive state using the `Signal` class
5
final count = Signal(0);
6
7
void increment() {
8
count.value++;
9
}
10
11
void decrement() {
12
count.value--;
13
}
14
}
counter_view.dart
25 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Provides the `CounterController` dependency to the widget tree
11
return ReactterProvider<CounterController>(
12
// Registers the `CounterController` dependency
13
() => CounterController(),
14
child: Scaffold(
15
appBar: AppBar(
16
title: const Text("Counter"),
17
),
18
body: const Center(
19
child: Counter(),
20
),
21
),
22
);
23
}
24
}
25
26
class Counter extends StatelessWidget {
27
final String? id;
28
29
const Counter({Key? key, this.id}) : super(key: key);
30
31
Widget build(BuildContext context) {
32
return ReactterConsumer<CounterController>(
33
// Locates the `CounterController` dependency by its identifier
34
id: id,
35
builder: (context, counterController, child) {
36
return Row(
37
mainAxisAlignment: MainAxisAlignment.center,
38
children: [
39
ElevatedButton(
40
onPressed: counterController.decrement,
41
child: const Icon(Icons.remove),
42
),
43
const SizedBox(width: 8),
44
ReactterConsumer<CounterController>(
45
// Locates the `CounterController` dependency by its identifier
46
id: id,
47
// Listens to the `count` state of the `CounterController` dependency
48
listenStates: (counterController) => [counterController.count],
49
// Passes the `child` widget to the `builder` function
50
child: Text("Count[$id]: "),
51
// Rebuilds whenever there are changes in the `count` state of the `CounterController` dependency
52
builder: (context, counterController, child) {
53
return Row(
54
children: [
55
child!,
56
Text("${counterController.count}"),
57
],
58
);
59
},
60
),
61
const SizedBox(width: 8),
62
ElevatedButton(
63
onPressed: counterController.increment,
64
child: const Icon(Icons.add),
65
),
66
],
67
);
68
},
69
);
70
}
71
}
main.dart
15 collapsed lines
1
import 'package:flutter/material.dart';
2
import 'counter_view.dart';
3
4
void main() {
5
runApp(MyApp());
6
}
7
8
class MyApp extends StatelessWidget {
9
@override
10
Widget build(BuildContext context) {
11
return MaterialApp(
12
home: CounterView(),
13
);
14
}
15
}

In the example above, the ReactterConsumer widget uses the child property to pass the Text widget to the builder function.