Skip to content

RtConsumer

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

Syntax

RtConsumer<T>({
Key? key,
String? id,
Widget? child,
bool listenAll = false,
List<RtState> 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 remains static while the widget tree is rebuilt. 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 : An optional function that returns a list of state( RtState ) 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 rebuilds a widget depending on the RtConsumer . It receives the following arguments:
    • context: The BuildContext of the RtConsumer widget.
    • instance: The instance of T dependency provided by the closest RtProvider widget.
    • child: The child widget passed to RtConsumer .

Usage

Basic Usage

To use RtConsumer , you need to provide the T dependency using the RtProvider widget.

Here’s an example of how to use it:

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
const Counter({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Locale the `CounterController` dependency
11
return RtConsumer<CounterController>(
12
builder: (context, counterController, child) {
16 collapsed lines
13
return Row(
14
mainAxisSize: MainAxisSize.min,
15
children: [
16
ElevatedButton(
17
onPressed: counterController.decrement,
18
child: const Icon(Icons.remove),
19
),
20
const SizedBox(width: 8),
21
Text("${counterController.count}"),
22
const SizedBox(width: 8),
23
ElevatedButton(
24
onPressed: counterController.increment,
25
child: const Icon(Icons.add),
26
),
27
],
28
);
29
},
30
);
31
}
32
}
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_view.dart';
4
import 'counter_controller.dart';
5
6
void main() {
7
runApp(MyApp());
8
}
9
10
class MyApp extends StatelessWidget {
11
@override
12
Widget build(BuildContext context) {
13
return MaterialApp(
14
// Provide the `CounterController` dependency to the widget tree
15
home: RtProvider.lazy(
16
() => CounterController(),
17
builder: (context, child) {
18
return CounterView();
19
},
20
),
21
);
22
}
23
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: Center(
14
child: Counter(),
15
),
16
);
17
}
18
}
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
}

In the example above, RtConsumer 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

To listen to all states, set the listenAll property to true . This ensures that RtConsumer rebuilds whenever any state in the dependency changes.

Here’s an example of how to use it:

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
const Counter({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Listens to all states provided by the `CounterController` dependency
11
// and rebuilds whenever there are changes any state of the `CounterController` dependency
12
return RtConsumer<CounterController>(
13
listenAll: true,
14
builder: (context, counterController, child) {
16 collapsed lines
15
return Row(
16
mainAxisSize: MainAxisSize.min,
17
children: [
18
ElevatedButton(
19
onPressed: counterController.decrement,
20
child: const Icon(Icons.remove),
21
),
22
const SizedBox(width: 8),
23
Text("${counterController.count}"),
24
const SizedBox(width: 8),
25
ElevatedButton(
26
onPressed: counterController.increment,
27
child: const Icon(Icons.add),
28
),
29
],
30
);
31
},
32
);
33
}
34
}
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_view.dart';
4
import 'counter_controller.dart';
5
6
void main() {
7
runApp(MyApp());
8
}
9
10
class MyApp extends StatelessWidget {
11
@override
12
Widget build(BuildContext context) {
13
return MaterialApp(
14
// Provide the `CounterController` dependency to the widget tree
15
home: RtProvider.lazy(
16
() => CounterController(),
17
builder: (context, child) {
18
return CounterView();
19
},
20
),
21
);
22
}
23
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: Center(
14
child: Counter(),
15
),
16
);
17
}
18
}
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
}

In the example above, RtConsumer 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 RtConsumer , utilizing either active or non-active listening as appropriate, e.g.:

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
const Counter({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Locale the `CounterController` dependency
11
return RtConsumer<CounterController>(
12
builder: (context, counterController, child) {
13
return Row(
14
mainAxisSize: MainAxisSize.min,
15
children: [
16
ElevatedButton(
17
onPressed: counterController.decrement,
18
child: const Icon(Icons.remove),
19
),
20
const SizedBox(width: 8),
21
// Listens to all states provided by the `CounterController` dependency
22
// and rebuilds whenever there are changes any state of the `CounterController` dependency
23
RtConsumer<CounterController>(
24
listenAll: true,
25
builder: (context, counterController, child) {
26
return Text("${counterController.count}");
27
},
28
),
29
const SizedBox(width: 8),
30
ElevatedButton(
31
onPressed: counterController.increment,
32
child: const Icon(Icons.add),
33
),
34
],
35
);
36
},
37
);
38
}
39
}
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_view.dart';
4
import 'counter_controller.dart';
5
6
void main() {
7
runApp(MyApp());
8
}
9
10
class MyApp extends StatelessWidget {
11
@override
12
Widget build(BuildContext context) {
13
return MaterialApp(
14
// Provide the `CounterController` dependency to the widget tree
15
home: RtProvider.lazy(
16
() => CounterController(),
17
builder: (context, child) {
18
return CounterView();
19
},
20
),
21
);
22
}
23
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: Center(
14
child: Counter(),
15
),
16
);
17
}
18
}
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
}

Listening to specific states

To listen to specific states, use the listenStates property. Define a function that returns a list of the states you want to listen to. This ensures that RtConsumer rebuilds only when the specified states change.

Here’s an example of how to use it:

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
const Counter({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Locale the `CounterController` dependency
11
return RtConsumer<CounterController>(
12
builder: (context, counterController, child) {
13
return Row(
14
mainAxisSize: MainAxisSize.min,
15
children: [
16
ElevatedButton(
17
onPressed: counterController.decrement,
18
child: const Icon(Icons.remove),
19
),
20
const SizedBox(width: 8),
21
// Observe the `count` property of the `counterController`
22
// and rebuild the widget tree when the `count` value changes
23
RtConsumer<CounterController>(
24
listenStates: (counterController) => [counterController.count],
25
builder: (context, counterController, child) {
26
return Text("${counterController.count}");
27
},
28
),
29
const SizedBox(width: 8),
30
ElevatedButton(
31
onPressed: counterController.increment,
32
child: const Icon(Icons.add),
33
),
34
],
35
);
36
},
37
);
38
}
39
}
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_view.dart';
4
import 'counter_controller.dart';
5
6
void main() {
7
runApp(MyApp());
8
}
9
10
class MyApp extends StatelessWidget {
11
@override
12
Widget build(BuildContext context) {
13
return MaterialApp(
14
// Provide the `CounterController` dependency to the widget tree
15
home: RtProvider.lazy(
16
() => CounterController(),
17
builder: (context, child) {
18
return CounterView();
19
},
20
),
21
);
22
}
23
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: Center(
14
child: Counter(),
15
),
16
);
17
}
18
}
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
}

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

Using id

RtConsumer offers the id property to locate the T dependency by its identifier. This is useful when you have multiple instances of the same dependency type and need to specify which one to use.

Here’s an example of how to use it:

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
final String? id;
7
8
const Counter({Key? key, this.id}) : super(key: key);
9
10
@override
11
Widget build(BuildContext context) {
12
// Locale the `CounterController` dependency
13
return RtConsumer<CounterController>(
14
id: id,
15
builder: (context, counterController, child) {
16
return Row(
17
mainAxisSize: MainAxisSize.min,
18
children: [
19
ElevatedButton(
20
onPressed: counterController.decrement,
21
child: const Icon(Icons.remove),
22
),
23
const SizedBox(width: 8),
24
// Observe the `count` property of the `counterController`
25
// and rebuild the widget tree when the `count` value changes
26
RtConsumer<CounterController>(
27
id: id,
28
listenStates: (counterController) => [counterController.count],
29
builder: (context, counterController, child) {
30
return Text("${counterController.count}");
31
},
32
),
33
const SizedBox(width: 8),
34
ElevatedButton(
35
onPressed: counterController.increment,
36
child: const Icon(Icons.add),
37
),
38
],
39
);
40
},
41
);
42
}
43
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: Center(
14
child: Column(
15
mainAxisAlignment: MainAxisAlignment.center,
16
children: [
17
const Counter(id: 'counter1'),
18
const SizedBox(height: 8),
19
const Counter(id: 'counter2'),
20
],
21
),
22
),
23
);
24
}
25
}
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_view.dart';
4
import 'counter_controller.dart';
5
6
void main() {
7
runApp(MyApp());
8
}
9
10
class MyApp extends StatelessWidget {
11
@override
12
Widget build(BuildContext context) {
13
return MaterialApp(
14
home: RtMultiProvider(
15
[
16
RtProvider(() => CounterController(), id: 'counter1'),
17
RtProvider(() => CounterController(), id: 'counter2'),
18
],
19
builder: (context, child) {
20
return CounterView();
21
},
22
),
23
);
24
}
25
}
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
}

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

Using child

RtConsumer offers the child property to pass a widget that is independent of the RtConsumer and is passed to the builder function. This is useful when you want to reuse a widget that does not need to rebuild when the dependency changes.

Here’s an example of how to use it:

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
final String? id;
7
8
const Counter({Key? key, this.id}) : super(key: key);
9
10
@override
11
Widget build(BuildContext context) {
12
// Locale the `CounterController` dependency
13
return RtConsumer<CounterController>(
14
id: id,
15
builder: (context, counterController, child) {
16
return Row(
17
mainAxisSize: MainAxisSize.min,
18
children: [
19
ElevatedButton(
20
onPressed: counterController.decrement,
21
child: const Icon(Icons.remove),
22
),
23
const SizedBox(width: 8),
24
// Observe the `count` property of the `counterController`
25
// and rebuild the widget tree when the `count` value changes
26
RtConsumer<CounterController>(
27
id: id,
28
listenStates: (counterController) => [counterController.count],
29
child: Text("Count[$id]: "),
30
builder: (context, counterController, child) {
31
return Row(
32
children: [
33
child!,
34
Text("${counterController.count}"),
35
],
36
);
37
},
38
),
39
const SizedBox(width: 8),
40
ElevatedButton(
41
onPressed: counterController.increment,
42
child: const Icon(Icons.add),
43
),
44
],
45
);
46
},
47
);
48
}
49
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: Center(
14
child: Column(
15
mainAxisAlignment: MainAxisAlignment.center,
16
children: [
17
const Counter(id: 'counter1'),
18
const SizedBox(height: 8),
19
const Counter(id: 'counter2'),
20
],
21
),
22
),
23
);
24
}
25
}
1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_view.dart';
4
import 'counter_controller.dart';
5
6
void main() {
7
runApp(MyApp());
8
}
9
10
class MyApp extends StatelessWidget {
11
@override
12
Widget build(BuildContext context) {
13
return MaterialApp(
14
home: RtMultiProvider(
15
[
16
RtProvider(() => CounterController(), id: 'counter1'),
17
RtProvider(() => CounterController(), id: 'counter2'),
18
],
19
builder: (context, child) {
20
return CounterView();
21
},
22
),
23
);
24
}
25
}
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
}

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