Skip to content

RtSelector

The RtSelector widget is a similarly to RtConsumer . It obtains the dependency provided by the closest RtProvider widget and allows you to select specific states to compute a value. This value will trigger a rebuild of the widget tree whenever it changes.

Syntax

RtSelector<T, V>({
Key? key,
String? id,
Widget? child,
required V selector(
T instance,
RtState select(RtState state),
),
required Widget builder(
BuildContext context,
T instance,
V value,
Widget? child,
),
})

Properties

  • key: An optional Key to use for identifying the widget.
  • id: An optional String to identify the selector.
  • child: An optional Widget that remains static while the widget tree is rebuilt. If defined, it is passed to the builder function.
  • selector : A function that computes a value V from one or more states and listens for changes to rebuild the widget tree when the value computed changes. It receives the following arguments:
    • instance: The instance of T dependency provided by the closest RtProvider widget.
    • select : A function that allows you to wrap the state( RtState ) to be listened for changes and returns it.
  • builder : A function that rebuilds a widget depending on the RtSelector . It receives the following arguments:
    • context: The BuildContext of the RtSelector widget.
    • instance: The instance of T dependency provided by the closest RtProvider widget.
    • value: The selected value computed V by the selector function.
    • child: The child widget passed to RtSelector .

Usage

Basic Usage

To use RtSelector , wrap it around the widget that you want to rebuild when the selected value changes.

Here’s an example of how to use it:

1
import 'package:flutter/widgets.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterDivisible extends StatelessWidget {
6
final int byNum;
7
8
const CounterDivisible({Key? key, required this.byNum}) : super(key: key);
9
10
@override
11
Widget build(BuildContext context) {
12
// Select the `count` state from the `CounterController`,
13
// calculate if the `count` is divisible by num(`byNum`)
14
// and rebuild the widget tree when the value(`isDivisibleByNum`) changes
15
return RtSelector<CounterController, bool>(
16
selector: (counterController, select) {
17
return select(counterController.count).value % byNum == 0;
18
},
19
builder: (context, counterController, isDivisibleByNum, child) {
20
print("Rebuild selector(byNum: $byNum): $isDivisibleByNum");
21
22
return Text(
23
isDivisibleByNum ? "Divisible by $byNum" : "Not divisible by $byNum",
24
);
25
},
26
);
27
}
28
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
import 'counter_divisible.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
return Scaffold(
11
appBar: AppBar(
12
title: const Text("Counter"),
13
),
14
body: Center(
15
child: Column(
16
mainAxisAlignment: MainAxisAlignment.center,
17
children: [
18
const Counter(),
19
SizedBox(height: 8),
20
const CounterDivisible(byNum: 2),
21
SizedBox(height: 8),
22
const CounterDivisible(byNum: 3),
23
SizedBox(height: 8),
24
const CounterDivisible(byNum: 5),
25
],
26
),
27
),
28
);
29
}
30
}
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: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 this example, checks if the count state from CounterController is divisible by a specified number (byNum). The RtSelector widget is used to perform this check and rebuild the widget tree whenever the divisibility status changes.

Using child

RtSelector offers the child property to pass a widget that is independent of the RtSelector and is passed to the builder function. This is useful when you want to reuse a widget.

Here’s an example of how to use it:

1
import 'package:flutter/widgets.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class CounterDivisible extends StatelessWidget {
6
final int byNum;
7
8
const CounterDivisible({Key? key, required this.byNum}) : super(key: key);
9
10
@override
11
Widget build(BuildContext context) {
12
// Select the `count` state from the `CounterController`,
13
// calculate if the `count` is divisible by num(`byNum`)
14
// and rebuild the widget tree when the value(`isDivisibleByNum`) changes
15
return RtSelector<CounterController, bool>(
16
selector: (counterController, select) {
17
return select(counterController.count).value % byNum == 0;
18
},
19
// Observe the `count` property of the `counterController`
20
// and rebuild the widget tree when the `count` value changes
21
child: RtConsumer<CounterController>(
22
listenStates: (counterController) => [counterController.count],
23
builder: (context, counterController, child) {
24
return Text("${counterController.count}");
25
},
26
),
27
builder: (context, counterController, isDivisibleByNum, child) {
28
print("Rebuild selector(byNum: $byNum): $isDivisibleByNum");
29
30
return Row(
31
mainAxisSize: MainAxisSize.min,
32
children: [
33
child!,
34
Text(
35
isDivisibleByNum
36
? " is divisible by $byNum"
37
: " is not divisible by $byNum",
38
),
39
],
40
);
41
},
42
);
43
}
44
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
import 'counter_divisible.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
return Scaffold(
11
appBar: AppBar(
12
title: const Text("Counter"),
13
),
14
body: Center(
15
child: Column(
16
mainAxisAlignment: MainAxisAlignment.center,
17
children: [
18
const Counter(),
19
SizedBox(height: 8),
20
const CounterDivisible(byNum: 2),
21
SizedBox(height: 8),
22
const CounterDivisible(byNum: 3),
23
SizedBox(height: 8),
24
const CounterDivisible(byNum: 5),
25
],
26
),
27
),
28
);
29
}
30
}
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: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 this example, checks if the count state from CounterController is divisible by a specified number (byNum). The child property in RtSelector is a RtConsumer widget that listens to changes in the count state and displays its value. This child widget remains static and does not rebuild when the divisibility status changes, optimizing performance.

Using id

RtSelector 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/widgets.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
4
import 'counter_controller.dart';
5
6
class CounterDivisible extends StatelessWidget {
7
final String? id;
8
final int byNum;
9
10
const CounterDivisible({
11
Key? key,
12
required this.byNum,
13
this.id,
14
}) : super(key: key);
15
16
@override
17
Widget build(BuildContext context) {
18
// Select the `count` state from the `CounterController`,
19
// calculate if the `count` is divisible by num(`byNum`)
20
// and rebuild the widget tree when the value(`isDivisibleByNum`) changes
21
return RtSelector<CounterController, bool>(
22
id: id,
23
selector: (counterController, select) {
24
return select(counterController.count).value % byNum == 0;
25
},
26
builder: (context, counterController, isDivisibleByNum, child) {
27
print(
28
"Rebuild selector(id: '$id', byNum: $byNum): $isDivisibleByNum",
29
);
30
31
return Text(
32
isDivisibleByNum ? "Divisible by $byNum" : "Not divisible by $byNum",
33
);
34
},
35
);
36
}
37
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
import 'counter_divisible.dart';
4
5
class CounterView extends StatelessWidget {
6
const CounterView({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
return Scaffold(
11
appBar: AppBar(
12
title: const Text("Counter"),
13
),
14
body: Center(
15
child: Column(
16
mainAxisAlignment: MainAxisAlignment.center,
17
children: const [
18
Counter(id: "Counter1"),
19
SizedBox(height: 8),
20
CounterDivisible(byNum: 2, id: "Counter1"),
21
SizedBox(height: 8),
22
CounterDivisible(byNum: 5, id: "Counter1"),
23
SizedBox(height: 16),
24
Counter(id: "Counter2"),
25
SizedBox(height: 8),
26
CounterDivisible(byNum: 3, id: "Counter2"),
27
],
28
),
29
),
30
);
31
}
32
}
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 '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: RtMultiProvider(
16
[
17
RtProvider.lazy(() => CounterController(), id: 'Counter1'),
18
RtProvider.lazy(() => CounterController(), id: 'Counter2'),
19
],
20
child: const CounterView(),
21
),
22
);
23
}
24
}
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 this example, every CounterDivisible widget checks if the count state from CounterController identified by id is divisible by a specified number (byNum). This flexibility ensures that the correct state data is used and displayed for each instance.